ftp.nice.ch/pub/next/unix/network/www/httpd.1.5-export.NIHS.bs.gnutar.gz#/httpd_1.5-export/src/http_request.c

This is http_request.c in view mode; [Download] [Up]

/************************************************************************
 * NCSA HTTPd Server
 * Software Development Group
 * National Center for Supercomputing Applications
 * University of Illinois at Urbana-Champaign
 * 605 E. Springfield, Champaign, IL 61820
 * httpd@ncsa.uiuc.edu
 *
 * Copyright  (C)  1995, Board of Trustees of the University of Illinois
 *
 ************************************************************************
 *
 * http_request.c,v 1.99 1995/11/06 20:58:09 blong Exp
 *
 ************************************************************************
 *
 * http_request.c: functions to get and process requests
 * 
 * 03-21-95  Based on NCSA HTTPd 1.3 by Rob McCool
 * 
 * 04-19-95 blong
 *      Forgot to remove free(remote_ip) from here, like elsewhere
 *
 * 04-20-95 blong
 *      Added patch "B18" for redirects w/o delay by Robert Hartill
 *
 * 05-01-95 blong
 *      Added patch by Steve Abatangle (sabat@enterprise.DTS.Harris.COM)
 *      to log SIGPIPE and timed out differently in send_fd_timed_out
 */


#include "config.h"
#include "portability.h"

#include <stdio.h>
#ifndef NO_STDLIB_H
# include <stdlib.h>
#endif /* NO_STDLIB_H */
#include <signal.h>
#include <sys/stat.h>
#include <setjmp.h>
#include <errno.h>
#include <string.h>
#include "constants.h"
#include "httpd.h"
#include "http_request.h"
#include "http_send.h"
#include "cgi.h"
#include "http_access.h"
#include "http_mime.h"
#include "http_config.h"
#include "host_config.h"
#include "http_log.h"
#include "http_auth.h"
#include "http_alias.h"
#include "env.h"
#include "util.h"

int no_headers;
int header_only;
per_request *gCurrentRequest;


/* If RFC931 identity check is on, the remote user name */
char *remote_logname;

/* Per request information */

char the_request[HUGE_STRING_LEN];
char as_requested[HUGE_STRING_LEN];
char failed_request[HUGE_STRING_LEN];
char failed_url[HUGE_STRING_LEN];

char *methods[METHODS] = {"GET","HEAD","POST","PUT","DELETE","LINK","UNLINK"};
char *protocals[PROTOCALS] = {"HTTP","HTTP/0.9","HTTP/1.0","HTTP/1.1"};


per_request *initialize_request(per_request *reqInfo) 
{
    int RealInit = 0;
    per_request *newInfo;

    RealInit = (reqInfo == NULL) ? 1 : 0;

    newInfo = (per_request *) malloc(sizeof(per_request));
    newInfo->hostInfo = gConfiguration;
 
    if (RealInit) {
	reqInfo = newInfo;
	reqInfo->ownURL = TRUE;
	reqInfo->ownDNS = TRUE;
	reqInfo->dns_host_lookup = FALSE;
	reqInfo->remote_name = NULL;
	reqInfo->remote_ip = NULL;
	reqInfo->remote_host = NULL;
	reqInfo->next = NULL;
    } else {
	newInfo->next = reqInfo;
	reqInfo = newInfo;
	reqInfo->ownURL = FALSE;
	reqInfo->ownDNS = FALSE;
	reqInfo->dns_host_lookup = reqInfo->next->dns_host_lookup;
	reqInfo->remote_name = reqInfo->next->remote_name;
	reqInfo->remote_host = reqInfo->next->remote_host;
	reqInfo->remote_ip = reqInfo->next->remote_ip;
	reqInfo->hostInfo = reqInfo->next->hostInfo;
    }

    /* Can't think (now) of any case where environment should transfer
       from last request during KeepAlive, but in other cases, perhaps */

    reqInfo->ownENV = TRUE;
    reqInfo->env = NULL;
    reqInfo->env_len = NULL;
    reqInfo->num_env = 0;
    reqInfo->max_env = 0;

    /* initialize auth stuff */
    reqInfo->bNotifyDomainRestricted = 0;
    reqInfo->bSatisfiedDomain = 0;

    reqInfo->auth_name = "ByPassword";
    reqInfo->auth_pwfile = NULL;
    reqInfo->auth_pwfile_type = 0;
    reqInfo->auth_grpfile = NULL;
    reqInfo->auth_grpfile_type = 0;
#ifdef DIGEST_AUTH
    reqInfo->auth_digestfile = NULL;
    reqInfo->auth_digestfile_type = 0;
#endif /* DIGEST_AUTH */

   /* eventually, we'll figure out how to let send_fd_timed_out know
      which request.  Until then, keep a global pointer to list */

    gCurrentRequest = reqInfo;

   /* reset security information to access config defaults */
    reset_security();

   /* Initialize Error codes */ 
    ErrorStat = 0;
/*    status = 200; */
    reqInfo->status = SC_DOCUMENT_FOLLOWS;
/*    reqInfo->status_line = NULL; */
    reqInfo->bytes_sent = -1;

    reqInfo->auth_type[0] = '\0';

    if (!reqInfo->ownURL) {
	strcpy(reqInfo->url, reqInfo->next->url);
	strcpy(reqInfo->args, reqInfo->next->args);
	strcpy(reqInfo->filename, reqInfo->next->filename);
    }
    reqInfo->url[0] = '\0';
    reqInfo->args[0] = '\0';
    reqInfo->filename[0] = '\0';

    reqInfo->agent[0] = '\0';
    reqInfo->referer[0] = '\0';

    init_header_vars(reqInfo);
    as_requested[0] = '\0';
    failed_url[0] = '\0';
    failed_request[0] = '\0';
    local_default_type[0] = '\0';
    local_default_icon[0] = '\0';

/* All but HEAD send more than a header */
    header_only = 0;

    /* reset keep-alive, client will indicate desire on next request */
    keep_alive.bKeepAlive = 0;
    
    return reqInfo;
}

per_request *continue_request(per_request *reqInfo, int options) {
    per_request *newInfo;

    newInfo = (per_request *)malloc(sizeof(per_request));
    newInfo->status = reqInfo->status;

    if (options & KEEP_ENV) {
	newInfo->ownENV = FALSE;
	newInfo->env = reqInfo->env;
	newInfo->env_len = reqInfo->env_len;
	newInfo->num_env = reqInfo->num_env;
	newInfo->max_env = reqInfo->max_env;
    } else {
        newInfo->ownENV = TRUE;
        newInfo->env = NULL;
        newInfo->env_len = NULL;
        newInfo->num_env = 0;
        newInfo->max_env = 0;
    }

    if (options & KEEP_AUTH) {
	strcpy(newInfo->auth_type,reqInfo->auth_type);
	newInfo->auth_name = reqInfo->auth_name;
	newInfo->auth_pwfile = reqInfo->auth_pwfile;
	newInfo->auth_grpfile = reqInfo->auth_grpfile;
	newInfo->auth_pwfile_type = reqInfo->auth_pwfile_type;
	newInfo->auth_grpfile_type = reqInfo->auth_grpfile_type;
#ifdef DIGEST_AUTH
	newInfo->auth_digestfile = reqInfo->auth_digestfile;
	newInfo->auth_digestfile_type = newInfo->auth_digestfile_type;
#endif /* DIGEST_AUTH */
	newInfo->bSatisfiedDomain = reqInfo->bSatisfiedDomain;
    } else {
        newInfo->auth_type[0] = '\0';
        newInfo->auth_name = NULL;
        newInfo->auth_pwfile = NULL;
        newInfo->auth_grpfile = NULL;
        newInfo->auth_pwfile_type = 0;
        newInfo->auth_grpfile_type = 0;
#ifdef DIGEST_AUTH
        newInfo->auth_digestfile = NULL;
        newInfo->auth_digestfile_type = 0;
#endif /* DIGEST_AUTH */
        newInfo->bSatisfiedDomain = FALSE;
    }
    newInfo->bNotifyDomainRestricted = reqInfo->bNotifyDomainRestricted;	
    newInfo->bytes_sent = 0;

    if (options & FORCE_GET) {
	if (reqInfo->method != M_HEAD) newInfo->method = M_GET;
	else newInfo->method = M_HEAD;
    } else {
	newInfo->method = reqInfo->method;
    }
    
    newInfo->http_version = reqInfo->http_version;

    if (options & NEW_DNS) {
	newInfo->ownDNS = TRUE;
	newInfo->dns_host_lookup = FALSE;
	newInfo->remote_host = NULL;
	newInfo->remote_name = NULL;
	newInfo->remote_ip = NULL;
	newInfo->hostInfo = NULL;
    } else {
	newInfo->ownDNS = FALSE;
	newInfo->dns_host_lookup = reqInfo->dns_host_lookup;
	newInfo->remote_host = reqInfo->remote_host;
	newInfo->remote_name = reqInfo->remote_name;
	newInfo->remote_ip = reqInfo->remote_ip;
	newInfo->hostInfo = reqInfo->hostInfo;
    }

    if (options & NEW_URL) {
	newInfo->ownURL = TRUE;
	newInfo->url[0] = '\0';
	newInfo->args[0] = '\0';
	newInfo->filename[0] = '\0';
    } else {
	newInfo->ownURL = FALSE;
	strcpy(newInfo->url, reqInfo->url);
	strcpy(newInfo->args, reqInfo->args);
	strcpy(newInfo->filename, reqInfo->filename);
    }

    strcpy(newInfo->referer,reqInfo->referer);
    strcpy(newInfo->agent,reqInfo->agent);

    newInfo->connection_socket = reqInfo->connection_socket;
    newInfo->out = reqInfo->out;

    newInfo->next = reqInfo;

    gCurrentRequest = newInfo;
    return newInfo;
}

void free_request(per_request *reqInfo,int options) {
    per_request *tmp = reqInfo;

    while (reqInfo != NULL) {
	if (reqInfo->ownDNS) {
	    if (reqInfo->remote_name != NULL) free(reqInfo->remote_name);
	    if (reqInfo->remote_host != NULL) free(reqInfo->remote_host);
	    if (reqInfo->remote_ip != NULL) free(reqInfo->remote_ip);
	}
	
	if (reqInfo->ownENV && reqInfo->env) {
	  free_env(reqInfo); 
	}
	tmp = reqInfo->next;
	free(reqInfo);
	reqInfo = tmp;
	gCurrentRequest = reqInfo;	
	if (options & ONLY_LAST) return;
    }
}
	     
void decode_request(per_request *reqInfo, char *request) 
{
    char *protocal;
    char *method, *url;
    char *chp;

    /* extract the method */
    method = strtok (request, "\t ");
    if (method) {
	if ((reqInfo->method = MapMethod (method)) == M_INVALID)
	    die(reqInfo,SC_BAD_REQUEST,"Invalid or unsupported method.");
    }
    else
	die(reqInfo,SC_BAD_REQUEST,"Invalid or unsupported method.");
    
    /* extract the URL, and args if present */
    url = strtok (NULL, "\t\r ");
    if (url && (chp = strchr (url, '?'))) {
	*chp++ = '\0';
	strcpy (reqInfo->args, chp);
    }
    strcpy (reqInfo->url, url);

    protocal = strtok (NULL, "\r");

    if(!protocal) {
        no_headers = 1;
        reqInfo->http_version = P_HTTP_0_9;
    }
    else {
        no_headers = 0;
        if (!strcmp(protocal,"HTTP/1.0")) 
	    reqInfo->http_version = P_HTTP_1_0;
	else if (!strcmp(protocal,"HTTP/1.1")) 
	    reqInfo->http_version = P_HTTP_1_1;
	else reqInfo->http_version = P_OTHER;

	/* dummy call to eat LF at end of protocal */
	strtok (NULL, "\n");
        get_mime_headers(reqInfo);
    }

/*    fprintf(stderr,"method:%s url:%s args:%s prot:%s\n",method,
	    reqInfo->url,reqInfo->args, protocal); */
} 


void get_request(per_request *reqInfo) 
{

    signal(SIGPIPE,send_fd_timed_out);


    if (getline(reqInfo->connection_socket, as_requested, HUGE_STRING_LEN,
		1, timeout) == -1)
        return;

    if(!as_requested[0]) 
        return;

    strcpy(the_request, as_requested);

#ifdef SETPROCTITLE
    setproctitle(the_request); 
#endif /* SETPROCTITLE */
    decode_request(reqInfo, as_requested);
    unescape_url(reqInfo->url);

    /* Moved this to later so we can read the headers first for HTTP/1.1
       Host: support */
    which_host_conf(reqInfo);
    if (reqInfo->ownDNS) {
      /* Only when ownDNS set do we find out the remote host name info
	 and by which name the server was called */
      get_remote_host(reqInfo);
    }

    if(reqInfo->method == M_HEAD) 
        header_only=1;
    else if(reqInfo->method == M_GET) {
    }

    process_request(reqInfo);

}

int MapMethod (char* method)
{
    if(!strcmp(method,"HEAD"))
	return M_HEAD;
    else if(!strcmp(method,"GET"))
	return M_GET;
    else if(!strcmp(method,"POST"))
	return M_POST;
    else if(!strcmp(method,"PUT"))
	return M_PUT;
    else if(!strcmp(method,"DELETE"))
	return M_DELETE;
    else 
	return M_INVALID;
}

/* Split from get_request (the former process_request) so that we can call 
   this from other places (on LOCAL_REDIRECTs and ErrorDocument handling) */

void process_request(per_request *reqInfo) 
{
    int s;

    s = translate_name(reqInfo,reqInfo->url,reqInfo->filename);

    switch(s) {
      case A_STD_DOCUMENT:
	if ((reqInfo->method == M_HEAD) && 
	    (reqInfo->http_version == P_HTTP_0_9)) {
	    header_only = 0;
	    reqInfo->method = M_GET;
	    die(reqInfo,SC_BAD_REQUEST,"Invalid HTTP/0.9 method.");
	}
	send_node(reqInfo);
	break;
      case A_REDIRECT_TEMP:
	die(reqInfo,SC_REDIRECT_TEMP,reqInfo->filename);
	break;
      case A_REDIRECT_PERM:
	die(reqInfo,SC_REDIRECT_PERM,reqInfo->filename);
	break;
      case A_SCRIPT_CGI:
	exec_cgi_script(reqInfo);
	break;
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.