Exemplo n.º 1
0
/*
 *	ic_connect()
 *	------------
 *	Connect to the Interchange server
 */
static BUFF *ic_connect(request_rec *r,ic_conf_rec *conf_rec)
{
	BUFF *ic_buff;
	ic_socket_rec *sock_rec;
	int ic_sock,retry,srv;
	int connected = 0;

	/*
	 *	connect the new socket to the Interchange server
	 *
	 *	if the connection to the Interchange server fails then
	 *	retry IC_DEFAULT_CONNECT_TRIES times, sleeping for
	 *	IC_DEFAULT_CONNECT_RETRY_DELAY seconds between each retry
	 */
	for (retry = 0; retry != conf_rec->connect_tries; retry++){
		for (srv = 0; srv != IC_MAX_SERVERS; srv++){
			if ((sock_rec = conf_rec->server[srv]) == NULL)
				break;
			if (srv){
				ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"Attempting to connect to backup server %d",srv);
			}

			/*
			 *	attempt to connect to the Interchange server
			 */
			ic_sock = ap_psocket(r->pool,sock_rec->family,SOCK_STREAM,0);
			if (ic_sock < 0){
				ap_log_reason("socket",r->uri,r);
				return NULL;
			}
			ap_hard_timeout("ic_connect",r);
			if (connect(ic_sock,sock_rec->sockaddr,sock_rec->size) >= 0){
				connected++;
				break;
			}
			ap_kill_timeout(r);
			ap_pclosesocket(r->pool,ic_sock);
		}
		if (connected)
			break;
		sleep(conf_rec->connect_retry_delay);
	}
	ap_kill_timeout(r);
	if (retry == conf_rec->connect_tries){
		ap_log_reason("Connection failed",r->uri,r);
		return NULL;
	}

	/*
	 *	create an Apache BUFF structure for our new connection
	 */
	ic_buff = ap_bcreate(r->pool,B_RDWR|B_SOCKET);
	if (!ic_buff){
		ap_log_reason("failed to create BUFF",r->uri,r);
		return NULL;
	}
	ap_bpushfd(ic_buff,ic_sock,ic_sock);
	return ic_buff;
}
Exemplo n.º 2
0
/**
 * gets content if this is notification.
 */
static int content_read(request_rec *r, char **rbuf)
{
    int rc;
    int rsize, len_read, rpos = 0;

    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) {
	return -1;
    }

    if (ap_should_client_block(r)) {
	char argsbuffer[HUGE_STRING_LEN];
	long length = r->remaining;
	*rbuf = ap_pcalloc(r->pool, length+1);
	ap_hard_timeout("content_read", r);

	while ((len_read = ap_get_client_block(r, argsbuffer,
	    sizeof(argsbuffer))) > 0)
	{
	    ap_reset_timeout(r);

	    if ((rpos + len_read) > length) {
		rsize = length -rpos;
	    } else {
		rsize = len_read;
	    }

	    memcpy((char*) *rbuf + rpos, argsbuffer, rsize);
	    rpos = rpos + rsize;
	}

	ap_kill_timeout(r);
    }
    am_web_log_debug("in content_read: rpos=%d", rpos);
    return rpos;
}
Exemplo n.º 3
0
static int do_print( void *_c, const char *buf, int len ) {
	mcontext *c = (mcontext*)_c;
	ap_soft_timeout("Client Timeout",c->r);
	send_headers(c);
	ap_rwrite(buf,len,c->r);
	ap_kill_timeout(c->r);
	return c->r->connection->aborted == 0;
}
Exemplo n.º 4
0
static void request_print( const char *data, int size, void *_c ) {
	mcontext *c = (mcontext *)_c;
	if( c == NULL ) c = CONTEXT();
	if( size == -1 ) size = (int)strlen(data);
	ap_soft_timeout("Client Timeout",c->r);
	send_headers(c);
	ap_rwrite(data,size,c->r);
	ap_kill_timeout(c->r);
}
Exemplo n.º 5
0
void ssl_io_suck(request_rec *r, SSL *ssl)
{
    int rc;
    int len;
    char *buf;
    int buflen;
    char c;
    int sucked;

    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) == OK) {
        if (ap_should_client_block(r)) {

            /* read client request block through Apache API */
            buflen = HUGE_STRING_LEN;
            buf = ap_palloc(r->pool, buflen);
            ap_hard_timeout("SSL I/O request body pre-sucking", r);
            sucked = 0;
            ssl_io_suck_start(r);
            while ((len = ap_get_client_block(r, buf, buflen)) > 0) {
                ssl_io_suck_record(r, buf, len);
                sucked += len;
                ap_reset_timeout(r);
            }
            ssl_io_suck_end(r);
            ap_kill_timeout(r);

            /* suck trailing data (usually CR LF) which 
               is still in the Apache BUFF layer */
            ap_hard_timeout("SSL I/O request trailing data pre-sucking", r);
            while (ap_bpeekc(r->connection->client) != EOF) {
                c = ap_bgetc(r->connection->client);
                ssl_io_suck_record(r, &c, 1);
                sucked++;
            }
            ap_kill_timeout(r);

            ssl_log(r->server, SSL_LOG_TRACE, 
                    "I/O: sucked %d bytes of input data from SSL/TLS I/O layer "
                    "for delayed injection into Apache I/O layer", sucked);
        }
    }
    return;
}
Exemplo n.º 6
0
static int util_read(ApacheRequest *req, const char **rbuf)
{
    request_rec *r = req->r;
    int rc = OK;

    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
	return rc;
    }

    if (ap_should_client_block(r)) {
	char buff[HUGE_STRING_LEN];
	int rsize, len_read, rpos=0;
	long length = r->remaining;

	if (length > req->post_max && req->post_max > 0) {
	    ap_log_rerror(REQ_ERROR, "[libapreq] entity too large (%d, max=%d)",
			  (int)length, req->post_max);
	    return HTTP_REQUEST_ENTITY_TOO_LARGE;
	}

	*rbuf = ap_pcalloc(r->pool, length + 1);

	ap_hard_timeout("[libapreq] util_read", r);

	while ((len_read =
		ap_get_client_block(r, buff, sizeof(buff))) > 0) {
	    if ((rpos + len_read) > length) {
		rsize = length - rpos;
	    }
	    else {
		rsize = len_read;
	    }
	    memcpy((char*)*rbuf + rpos, buff, rsize);
	    rpos += rsize;
	}

	ap_kill_timeout(r);
    }

    return rc;
}
Exemplo n.º 7
0
static int suphp_handler(request_rec *r) {
    suphp_conf *sconf;
    suphp_conf *dconf;

#ifdef SUPHP_USE_USERGROUP
    char *ud_user = NULL;
    char *ud_group = NULL;
    int ud_success = 0;
#endif

    struct stat finfo;

    int rv;

    char *auth_user = NULL;
    char *auth_pass = NULL;

    pool *p;

    BUFF *script_in, *script_out, *script_err;

    const char *handler;

    sconf = ap_get_module_config(r->server->module_config, &suphp_module);
    dconf = ap_get_module_config(r->per_dir_config, &suphp_module);

    p = r->main ? r->main->pool : r->pool;

    /* only handle request if mod_suphp is active for this handler */
    /* check only first byte of value (second has to be \0) */
    if (r->handler != NULL) {
        handler = r->handler;
    } else {
        handler = r->content_type;
    }
    if ((ap_table_get(dconf->handlers, handler) == NULL)) {
        if ((ap_table_get(sconf->handlers, handler) == NULL)
            || (*(ap_table_get(sconf->handlers, handler)) == '0')) {
            return DECLINED;
        }
    } else if (*(ap_table_get(dconf->handlers, handler)) == '0') {
        return DECLINED;
    }

    /* check if suPHP is enabled for this request */

    if (((sconf->engine != SUPHP_ENGINE_ON)
         && (dconf->engine != SUPHP_ENGINE_ON))
        || ((sconf->engine == SUPHP_ENGINE_ON)
            && (dconf->engine == SUPHP_ENGINE_OFF)))
        return DECLINED;

    /* check if file is existing and accessible */

    rv = stat(ap_pstrdup(p, r->filename), &finfo);
    if (rv == 0) {
        ; /* do nothing */
    } else if (errno == EACCES) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "access to %s denied",
                      r->filename);
        return HTTP_FORBIDDEN;
    } else if (errno == ENOENT || errno == ENOTDIR) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "File does not exist: %s",
                      r->filename);
        return HTTP_NOT_FOUND;
    } else {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "could not get fileinfo: %s",
                      r->filename);
        return HTTP_NOT_FOUND;
    }

#ifdef SUPHP_USE_USERGROUP
    if ((sconf->target_user == NULL || sconf->target_group == NULL)
        && (dconf->target_user == NULL || dconf->target_group == NULL)) {

        /* Identify mod_userdir request
           As Apache 1.3 does not yet provide a clean way to see
           whether a request was handled by mod_userdir, we assume
           this is true for any request beginning with ~ */

        int ud_success = 0; /* set to 1 on success */

        if (!strncmp("/~", r->uri, 2)) {
            char *username = ap_pstrdup(r->pool, r->uri + 2);
            char *pos = strchr(username, '/');
            if (pos) {
                *pos = 0;
                if (strlen(username)) {
                    struct passwd *pw;
                    struct group *gr;
                    gid_t gid;
                    char *grpname;
                    if ((pw = getpwnam(username)) != NULL) {
                        gid = pw->pw_gid;

                        if ((gr = getgrgid(gid)) != NULL) {
                            grpname = gr->gr_name;
                        } else {
                            if ((grpname = ap_palloc(r->pool, 16)) == NULL) {
                                return HTTP_INTERNAL_SERVER_ERROR;
                            }
                            ap_snprintf(grpname, 16, "#%ld", (long) gid);
                        }

                        ud_user = username;
                        ud_group = grpname;
                        ud_success = 1;
                    }
                }
            }
        }

        if (!ud_success) {
            /* This is not a userdir request and user/group are not
               set, so log the error and return */
            ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
                          "No user or group set - set suPHP_UserGroup");
            return HTTP_INTERNAL_SERVER_ERROR;
        }
    }
#endif /* SUPHP_USE_USERGROUP */


    /* prepare environment for new process */

    ap_add_common_vars(r);
    ap_add_cgi_vars(r);

    ap_table_unset(r->subprocess_env, "SUPHP_PHP_CONFIG");
    ap_table_unset(r->subprocess_env, "SUPHP_AUTH_USER");
    ap_table_unset(r->subprocess_env, "SUPHP_AUTH_PW");

#ifdef SUPHP_USE_USERGROUP
    ap_table_unset(r->subprocess_env, "SUPHP_USER");
    ap_table_unset(r->subprocess_env, "SUPHP_GROUP");
    ap_table_unset(r->subprocess_env, "SUPHP_USERDIR_USER");
    ap_table_unset(r->subprocess_env, "SUPHP_USERDIR_GROUP");
#endif /* SUPHP_USE_USERGROUP */

    if (dconf->php_config) {
        ap_table_set(r->subprocess_env, "SUPHP_PHP_CONFIG", dconf->php_config);
    }

    ap_table_set(r->subprocess_env, "SUPHP_HANDLER", handler);

    if (r->headers_in) {
        const char *auth;
        auth = ap_table_get(r->headers_in, "Authorization");
        if (auth && auth[0] != 0 && strncmp(auth, "Basic ", 6) == 0) {
            char *user;
            char *pass;
            user = ap_pbase64decode(p, auth + 6);
            if (user) {
                pass = strchr(user, ':');
                if (pass) {
                    *pass++ = '\0';
                    auth_user = ap_pstrdup(p, user);
                    auth_pass = ap_pstrdup(p, pass);
                }
            }
        }
    }

    if (auth_user && auth_pass) {
        ap_table_setn(r->subprocess_env, "SUPHP_AUTH_USER", auth_user);
        ap_table_setn(r->subprocess_env, "SUPHP_AUTH_PW", auth_pass);
    }

#ifdef SUPHP_USE_USERGROUP
    if (dconf->target_user) {
        ap_table_set(r->subprocess_env, "SUPHP_USER", dconf->target_user);
    } else if (sconf->target_user) {
        ap_table_set(r->subprocess_env, "SUPHP_USER", sconf->target_user);
    } else {
        ap_table_set(r->subprocess_env, "SUPHP_USER", ud_user);
    }

    if (dconf->target_group) {
        ap_table_set(r->subprocess_env, "SUPHP_GROUP", dconf->target_group);
    } else if (sconf->target_group) {
        ap_table_set(r->subprocess_env, "SUPHP_GROUP", sconf->target_group);
    } else {
        ap_table_set(r->subprocess_env, "SUPHP_GROUP", ud_group);
    }
    if (ud_success) {
	ap_table_set(r->subprocess_env, "SUPHP_USERDIR_USER", ud_user);
	ap_table_set(r->subprocess_env, "SUPHP_USERDIR_GROUP", ud_group);
    }
#endif /* SUPHP_USE_USERGROUP */

    /* Fork child process */

    if (!ap_bspawn_child(p, suphp_child, (void *) r, kill_after_timeout,
                         &script_in, &script_out, &script_err)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
                      "couldn't spawn child process for: %s", r->filename);
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    /* Transfer request body to script */

    if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) {
        /* Call failed, return status */
        return rv;
    }

    if (ap_should_client_block(r)) {
        char buffer[HUGE_STRING_LEN];
        int len_read;

        ap_hard_timeout("reading request body", r);

        while ((len_read = ap_get_client_block(r, buffer, HUGE_STRING_LEN))
               > 0) {
            ap_reset_timeout(r);
            if (ap_bwrite(script_in, buffer, len_read) < len_read) {
                /* silly script stopped reading, soak up remaining message */
                while (ap_get_client_block(r, buffer, HUGE_STRING_LEN) > 0) {
                    /* dump it */
                }
                break;
            }
        }

        ap_bflush(script_in);
        ap_kill_timeout(r);
    }

    ap_bclose(script_in);

    /* Transfer output from script to client */

    if (script_out) {
        const char *location;
        char hbuffer[MAX_STRING_LEN];
        char buffer[HUGE_STRING_LEN];

        rv = ap_scan_script_header_err_buff(r, script_out, hbuffer);
        if (rv == HTTP_NOT_MODIFIED) {
            return rv;
        } else if (rv) {
            return HTTP_INTERNAL_SERVER_ERROR;
        }

        location = ap_table_get(r->headers_out, "Location");
        if (location && r->status == 200) {
            /* Soak up all the script output */
            ap_hard_timeout("reading from script", r);
            while (ap_bgets(buffer, HUGE_STRING_LEN, script_out) > 0) {
                continue;
            }
            ap_kill_timeout(r);
            ap_bclose(script_out);
            ap_bclose(script_err);

            if (location[0] == '/') {
                /* Redirect has always GET method */
                r->method = ap_pstrdup(p, "GET");
                r->method_number = M_GET;

                /* Remove Content-Length - redirect should not read  *
                 * request body                                      */
                ap_table_unset(r->headers_in, "Content-Length");

                /* Do the redirect */
                ap_internal_redirect_handler(location, r);
                return OK;
            } else {
                /* Script did not set status 302 - so it does not want *
                 * to send its own body. Simply set redirect status    */
                return REDIRECT;
            }
        }

        /* Output headers and body */

        ap_send_http_header(r);
        if (!r->header_only) {
            ap_send_fb(script_out, r);
        }
        ap_bclose(script_out);
        /* Errors have already been logged by child */
        ap_bclose(script_err);
    }

    return OK;
}
Exemplo n.º 8
0
static int suphp_source_handler(request_rec *r) {
    suphp_conf *conf;
    int rv;
    pool *p;
    int fd;
    BUFF *script_in, *script_out, *script_err;
    char buffer[HUGE_STRING_LEN];

    if (strcmp(r->method, "GET")) {
        return DECLINED;
    }

    conf = ap_get_module_config(r->server->module_config, &suphp_module);
    if (conf->php_path == NULL) {
        return DECLINED;
    }

    p = r->main ? r->main->pool : r->pool;

    fd = open(r->filename, O_NOCTTY, O_RDONLY);
    if (fd != -1) {
        close(fd);
    } else if (errno == EACCES) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "access to %s denied",
                      r->filename);
        return HTTP_FORBIDDEN;
    } else if (errno == ENOENT || errno == ENOTDIR) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "File does not exist: %s",
                      r->filename);
        return HTTP_NOT_FOUND;
    } else {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "could open file: %s",
                      r->filename);
        return HTTP_NOT_FOUND;
    }

    /* Fork child process */

    if (!ap_bspawn_child(p, suphp_source_child, (void *) r, kill_after_timeout,
                         &script_in, &script_out, &script_err)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
                      "couldn't spawn child process for: %s", r->filename);
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    /* Read request body */

    if (ap_should_client_block(r)) {
        char buffer[HUGE_STRING_LEN];
        int len_read;

        ap_hard_timeout("reading request body", r);

        while (ap_get_client_block(r, buffer, HUGE_STRING_LEN) > 0) {
            ap_reset_timeout(r);
            // Ignore input
        }

        ap_bflush(script_in);
        ap_kill_timeout(r);
    }

    ap_bclose(script_in);

    /* Transfer output from PHP to client */

    if (script_out) {
        /* Output headers and body */

        r->content_type = "text/html";
        ap_send_http_header(r);
        if (!r->header_only) {
            ap_send_fb(script_out, r);
        }
        ap_bclose(script_out);
        /* Errors have already been logged by child */
        ap_bclose(script_err);
    }

    return OK;

}
Exemplo n.º 9
0
/* ====================================================================
 * Handles one attempt to transact with the app server.
 * Returns one of the following codes:
 *   0 = success
 *   1 = failure, but ok to try again
 *   2 = failure, and do not try again
 * ==================================================================== */
static int transact_with_app_server(request_rec *r, wkcfg* cfg, WFILE* whole_dict, WFILE* int_dict, long length)
{
    int sock = 0;
    BUFF* buffsocket;
    long bs;
    int ret;

    ap_hard_timeout("wk_send", r);

    sock = wksock_open(r, cfg->addr, cfg->port, cfg);
    if (sock <= 0) return 1;

    /* Errors after this point mean that the
     * whole request fails -- no retry is possible.
     * That's because once we've sent the request, it's possible
     * that the appserver has already started to work on the request,
     * and we don't want to accidentally submit the same request twice.
     */

    log_debug("creating buffsocket", r);
    buffsocket = ap_bcreate(r->pool, B_SOCKET+B_RDWR);

    log_debug("push socket into fd", r);
    ap_bpushfd(buffsocket, sock, sock);

    /* Now we send the request to the AppServer */
    log_debug("writing request to buff", r);
    bs = ap_bwrite(buffsocket, int_dict->str, int_dict->ptr - int_dict->str);
    bs = ap_bwrite(buffsocket, whole_dict->str, length);

    /* Now we pump through any client input. */
    if ((ret = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != 0)
        return 2;
    if (ap_should_client_block(r)) {
        char * buff = ap_pcalloc(r->pool, MAX_STRING_LEN);
        int n;
        int sent = 0;
        int retry = 0;

        while ((n = ap_get_client_block(r, buff, MAX_STRING_LEN)) > 0) {
            retry = 0;
            sent = 0;
            while (retry < 10) {
                sent = sent + ap_bwrite(buffsocket, buff+sent, n-sent);
                if (sent < n) {
                    retry++;
                    sleep(1);
                    log_error("Have to retry sending input to appserver", r->server);
                }
                else break;
                if (retry == 10) {
                    /* AppServer stopped reading */
                    /* absorb any remaining input */
                    while (ap_get_client_block(r, buff, MAX_STRING_LEN) > 0)
                        ; /* Dump it */
                    break;
                }
            }
        }
    }

    ap_bflush(buffsocket);
    /* Done sending */

    log_debug("Sent Request to client", r);

    /* Let the AppServer know we're done */
    shutdown(sock, 1);
    ap_kill_timeout(r);

    /* Now we get the response from the AppServer */
    ap_hard_timeout("wk_read", r);

    log_debug("scanning for headers", r);
    /* pull out headers */
    if ((ret = ap_scan_script_header_err_buff(r, buffsocket, NULL))) {
        if (ret >= 500 || ret < 0) {
            log_error("cannot scan servlet headers ", r->server);
            return 2;
        }

        r->status_line = NULL;
    }

    ap_send_http_header(r);

    /* now we just send the reply straight to the client */
    log_debug("Sending response", r);

    length = ap_send_fb(buffsocket, r);
    //sprintf(msgbuf, "Sent %i bytes to the client", length);
    //log_debug(msgbuf, r);

    /* Kill timeouts, close buffer and socket and return */
    ap_kill_timeout(r);

    log_debug("closing buffsocket", r);
    ap_bclose(buffsocket);

    log_debug("Done", r);

    return 0;
}
Exemplo n.º 10
0
static int handle_request(request_rec *r)
{
	tmcdreq_t tmcdreq, *reqp = &tmcdreq;
	tmcdresp_t *response = NULL;
	char *command;
	struct in_addr local_addr;
	struct in_addr remote_addr;
	struct sockaddr_in redir_client;
	int tmcd_status;
	int status = OK;
	char *status_line = NULL;
	char *args = NULL;
	char *function_args = NULL;
	char *p;
	char **argv = NULL;
	int argc, i;

	reqp->istcp = 1;
	reqp->isssl = 1; /* FIXME */

	if (strcmp(r->handler, "tmcd")) {
		status = DECLINED;
		goto err;
	}

#if 0
	r->allowed |= (AP_METHOD_BIT << M_GET);
	if (r->method_number != M_GET) {
		status = DECLINED;
		goto err;
	}
#endif

	memset(reqp, 0, sizeof(*reqp));

	local_addr = r->connection->local_addr.sin_addr;
	remote_addr = r->connection->remote_addr.sin_addr;

	reqp->version = 1; /* FIXME need sane default */
	tmcd_init(reqp, &local_addr, NULL);

	command = r->path_info;
	while (*command && *command == '/') {
		command++;
	}
	if (command[0] == '\0') {
		status = HTTP_BAD_REQUEST;
		goto err;
	}

	if (r->args) {
		args = malloc(strlen(r->args) + 1);
		if (args == NULL) {
			status = HTTP_INTERNAL_SERVER_ERROR;
			goto err;
		}

		strcpy(args, r->args);
		argv = make_argv(args, &argc, '&');
		if (argv == NULL) {
			status = HTTP_INTERNAL_SERVER_ERROR;
			goto err;
		}

		for (i = 0; i < argc; i++) {
			/* Unescape the arguments */
			p = args;
			while (*p) {
				if (*p == '+')
					*p = ' ';
				p++;
			}

			status = ap_unescape_url(args);
			if (status != OK) {
				goto err;
			}

			if (strncasecmp(argv[i], "version=", 8) == 0) {
				long version;
				char *end;
				version = strtol(argv[i] + 8, &end, 10);
				if (*end != '\0' || *(argv[i] + 8) == '\0') {
					status = HTTP_BAD_REQUEST;
					status_line = "Invalid Version";
					goto err;
				}

				reqp->version = version;
			} else if (strncasecmp(argv[i], "redirect=", 9) == 0) {
				if (inet_pton(AF_INET, argv[i] + 9,
				              &redir_client.sin_addr) <= 0) {
					status = HTTP_BAD_REQUEST;
					status_line = "Invalid IP Address";
					goto err;
				}
				/* FIXME info message */

				if (remote_addr.s_addr != local_addr.s_addr) {
					status = HTTP_FORBIDDEN;
					status_line = "Redirection Not Allowed";
					goto err;
				}

				remote_addr =
				    redir_client.sin_addr;

			} else if (strncasecmp(argv[i], "vnodeid=", 8) == 0) {
				if (strlen(argv[i] + 8) >=
				           sizeof(reqp->vnodeid)) {
					status = HTTP_BAD_REQUEST;
					status_line =
					    "Virtual Node ID Too Long";
					goto err;
				}
				reqp->isvnode = 1;
				strcpy(reqp->vnodeid, argv[i] + 8);
			} else if (strncasecmp(argv[i], "args=", 5) == 0) {
				function_args = argv[i] + 5;
			}
		}

	}

	/* FIXME handle wanodekey */
	if ((tmcd_status = iptonodeid(reqp, remote_addr, NULL))) {
		if (reqp->isvnode) {
			status_line = "Invalid Virtual Node";
		}
		else {
			status_line = "Invalid Node";
		}
		status = HTTP_NOT_FOUND;
		goto err;
	}

	if (reqp->tmcd_redirect[0]) {
		/* FIXME what if https should be used? */
		/* FIXME do I need to specify the args should be passed too? */
		char *uri = ap_psprintf(r->pool, "http://%s%s?%s", reqp->tmcd_redirect,
		                        r->uri, r->args);
		ap_table_setn(r->headers_out, "Location", uri);
		status = HTTP_MOVED_TEMPORARILY;
		goto done;
	}

	tmcd_status = tmcd_handle_request(reqp, &response, command,
	                                  function_args);

	if (tmcd_status == TMCD_STATUS_OK) {
		r->content_type = response->type;
		ap_set_content_length(r, response->length);
		/* FIXME doctype */
		ap_soft_timeout("tmcd response call trace", r);
		ap_send_http_header(r);
		ap_rprintf(r, "%s", response->data);
		ap_kill_timeout(r);
		status = OK;
		goto done;
	} else {
		switch(tmcd_status) {
			case TMCD_STATUS_UNKNOWN_COMMAND:
				status = HTTP_NOT_FOUND;
				status_line = "Unknown Command";
				break;
			case TMCD_STATUS_REQUIRES_ENCRYPTION:
				status = HTTP_FORBIDDEN;
				status_line = "SSL Required";
				break;
			case TMCD_STATUS_NODE_NOT_ALLOCATED:
				status = HTTP_FORBIDDEN;
				status_line = "Node Not Allocated";
				break;
			case TMCD_STATUS_COMMAND_FAILED:
				status = HTTP_INTERNAL_SERVER_ERROR;
				if (response && response->data) {
					status_line = response->data;
				}
				break;
			case TMCD_STATUS_MALLOC_FAILED:
				status = HTTP_INTERNAL_SERVER_ERROR;
				break;
		}

		goto err;
	}
err:
done:
	if (argv)
		free(argv);

	if (args)
		free(args);

	if (response)
		tmcd_free_response(response);

	if (status_line) {
		r->status_line = ap_psprintf(r->pool, "%3.3u %s", status,
		                             status_line);
	}
	return status;
}
Exemplo n.º 11
0
static PyObject * req_read(requestobject *self, PyObject *args)
{

    int rc, bytes_read, chunk_len;
    char *buffer;
    PyObject *result;
    int copied = 0;
    int len = -1;

    if (! PyArg_ParseTuple(args, "|i", &len)) 
	return NULL;

    if (len == 0) {
	return PyString_FromString("");
    }

    /* is this the first read? */
    if (! self->request_rec->read_length) {

	/* then do some initial setting up */

	rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);
	if(rc != OK) {
	    PyObject *val = PyInt_FromLong(rc);
	    if (val == NULL)
		return NULL;
	    PyErr_SetObject(Mp_ServerReturn, val);
	    Py_DECREF(val);
	    return NULL;
	}

	if (! ap_should_client_block(self->request_rec)) {
	    /* client has nothing to send */
	    return PyString_FromString("");
	}
    }

    if (len < 0)
	len = self->request_rec->remaining +
	    (self->rbuff_len - self->rbuff_pos);

    result = PyString_FromStringAndSize(NULL, len);

    /* possibly no more memory */
    if (result == NULL) 
	return NULL;

    buffer = PyString_AS_STRING((PyStringObject *) result);

    /* if anything left in the readline buffer */
    while ((self->rbuff_pos < self->rbuff_len) && (copied < len))
	buffer[copied++] = self->rbuff[self->rbuff_pos++];
    
    if (copied == len)
	return result; 	/* we're done! */

    /* set timeout */
    ap_soft_timeout("mod_python_read", self->request_rec);

    /* read it in */
    Py_BEGIN_ALLOW_THREADS
    chunk_len = ap_get_client_block(self->request_rec, buffer, len);
    Py_END_ALLOW_THREADS
    bytes_read = chunk_len;

    /* if this is a "short read", try reading more */
    while ((bytes_read < len) && (chunk_len != 0)) {
	Py_BEGIN_ALLOW_THREADS
	chunk_len = ap_get_client_block(self->request_rec, 
					buffer+bytes_read, len-bytes_read);
	Py_END_ALLOW_THREADS
	ap_reset_timeout(self->request_rec);
	if (chunk_len == -1) {
	    ap_kill_timeout(self->request_rec);
	    PyErr_SetObject(PyExc_IOError, 
			    PyString_FromString("Client read error (Timeout?)"));
	    return NULL;
	}
	else
	    bytes_read += chunk_len;
    }

    ap_kill_timeout(self->request_rec);

    /* resize if necessary */
    if (bytes_read < len) 
	if(_PyString_Resize(&result, bytes_read))
	    return NULL;

    return result;
}
Exemplo n.º 12
0
/*
 *	ic_transfer_response()
 *	----------------------
 *	Read the response from the Interchange server
 *	and relay it to the client
 */
static int ic_transfer_response(request_rec *r,BUFF *ic_buff)
{
	const char *location;
	int rc,ic_sock;
	char sbuf[MAX_STRING_LEN],argsbuffer[MAX_STRING_LEN];

	/*
	 *	get the socket we are using to talk to the
	 *	Interchange server, and wait for Interchange to
	 *	send us some data
	 */
	ic_sock = ap_bfileno(ic_buff,B_RD);
	rc = ic_select(ic_sock,0,IC_DEFAULT_TIMEOUT,0);
	if (rc < 0){
		ap_log_reason("Failed to select the response header",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	/*
	 *	check the HTTP header to make sure that it looks valid
	 */
	if ((rc = ap_scan_script_header_err_buff(r,ic_buff,sbuf)) != OK) {
		if (rc == HTTP_INTERNAL_SERVER_ERROR) {
			ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"Malformed header return by Interchange: %s",sbuf);
		}
		return rc;
	}

	/*
	 *	check the header for an HTTP redirect request
	 */
	location = ap_table_get(r->headers_out,"Location");
	if (r->status == 200 && location){
		fd_set sock_set;

		/*
		 *	check if we need to do an external redirect
		 */
		if (*location != '/')
			return REDIRECT;

		/*
		 *	we are here because we need to do an internal redirect
		 *
		 *	soak up any data from the Interchange socket
		 */
		rc = ic_select(ic_sock,0,IC_DEFAULT_TIMEOUT,0);
		if (rc < 0){
			ap_log_reason("Failed to select the response text",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}

		/*
		 *	soak up any body-text sent by the Interchange server
		 */
		ap_soft_timeout("mod_interchange: Interchange read",r);
		while (ap_bgets(argsbuffer,MAX_STRING_LEN,ic_buff) > 0)
			;
		ap_kill_timeout(r);

		/*
		 *	always use the GET method for internal redirects
		 *	also, unset the Content-Length so that nothing
		 *	else tries to re-read the text we just soaked up
		 */
		r->method = ap_pstrdup(r->pool,"GET");
		r->method_number = M_GET;
		ap_table_unset(r->headers_in,"Content-Length");
		ap_internal_redirect(location,r);
		return OK;
	}

	/*
	 *	we were not redirected, so send the HTTP headers
	 *	to the client
	 */
	ap_hard_timeout("mod_interchange: Client write",r);
	ap_send_http_header(r);
	if (ap_rflush(r) < 0){
		ap_log_reason("error sending headers to client",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	/*
	 *	if Interchange is sending body text (HTML), then
	 *	relay this to the client
	 */
	if (!r->header_only){
		ap_reset_timeout(r);
		if ((rc = ap_bnonblock(ic_buff,B_RD)) != 0){
			ap_log_reason("error turning non blocking I/O on Interchange socket",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		ap_bsetflag(ic_buff,B_SAFEREAD,1);
		if (ap_send_fb(ic_buff,r) <= 0){
			ap_log_reason("error sending response body to client",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}
	ap_kill_timeout(r);
	return OK;
}
Exemplo n.º 13
0
/* 
 * Sample content handler.  All this does is display the call list that has
 * been built up so far.
 *
 * The return value instructs the caller concerning what happened and what to
 * do next:
 *  OK ("we did our thing")
 *  DECLINED ("this isn't something with which we want to get involved")
 *  HTTP_mumble ("an error status should be reported")
 */
static int example_handler(request_rec *r)
{

    excfg *dcfg;

    dcfg = our_dconfig(r);
    trace_add(r->server, r, dcfg, "example_handler()");
    /*
     * We're about to start sending content, so we need to force the HTTP
     * headers to be sent at this point.  Otherwise, no headers will be sent
     * at all.  We can set any we like first, of course.  **NOTE** Here's
     * where you set the "Content-type" header, and you do so by putting it in
     * r->content_type, *not* r->headers_out("Content-type").  If you don't
     * set it, it will be filled in with the server's default type (typically
     * "text/plain").  You *must* also ensure that r->content_type is lower
     * case.
     *
     * We also need to start a timer so the server can know if the connexion
     * is broken.
     */
    r->content_type = "text/html";

    ap_soft_timeout("send example call trace", r);
    ap_send_http_header(r);
#ifdef CHARSET_EBCDIC
    /* Server-generated response, converted */
    ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, r->ebcdic.conv_out = 1);
#endif

    /*
     * If we're only supposed to send header information (HEAD request), we're
     * already there.
     */
    if (r->header_only) {
        ap_kill_timeout(r);
        return OK;
    }

    /*
     * Now send our actual output.  Since we tagged this as being
     * "text/html", we need to embed any HTML.
     */
    ap_rputs(DOCTYPE_HTML_3_2, r);
    ap_rputs("<HTML>\n", r);
    ap_rputs(" <HEAD>\n", r);
    ap_rputs("  <TITLE>mod_example Module Content-Handler Output\n", r);
    ap_rputs("  </TITLE>\n", r);
    ap_rputs(" </HEAD>\n", r);
    ap_rputs(" <BODY>\n", r);
    ap_rputs("  <H1><SAMP>mod_example</SAMP> Module Content-Handler Output\n", r);
    ap_rputs("  </H1>\n", r);
    ap_rputs("  <P>\n", r);
    ap_rprintf(r, "  Apache HTTP Server version: \"%s\"\n",
	    ap_get_server_version());
    ap_rputs("  <BR>\n", r);
    ap_rprintf(r, "  Server built: \"%s\"\n", ap_get_server_built());
    ap_rputs("  </P>\n", r);;
    ap_rputs("  <P>\n", r);
    ap_rputs("  The format for the callback trace is:\n", r);
    ap_rputs("  </P>\n", r);
    ap_rputs("  <DL>\n", r);
    ap_rputs("   <DT><EM>n</EM>.<SAMP>&lt;routine-name&gt;", r);
    ap_rputs("(&lt;routine-data&gt;)</SAMP>\n", r);
    ap_rputs("   </DT>\n", r);
    ap_rputs("   <DD><SAMP>[&lt;applies-to&gt;]</SAMP>\n", r);
    ap_rputs("   </DD>\n", r);
    ap_rputs("  </DL>\n", r);
    ap_rputs("  <P>\n", r);
    ap_rputs("  The <SAMP>&lt;routine-data&gt;</SAMP> is supplied by\n", r);
    ap_rputs("  the routine when it requests the trace,\n", r);
    ap_rputs("  and the <SAMP>&lt;applies-to&gt;</SAMP> is extracted\n", r);
    ap_rputs("  from the configuration record at the time of the trace.\n", r);
    ap_rputs("  <STRONG>SVR()</STRONG> indicates a server environment\n", r);
    ap_rputs("  (blank means the main or default server, otherwise it's\n", r);
    ap_rputs("  the name of the VirtualHost); <STRONG>DIR()</STRONG>\n", r);
    ap_rputs("  indicates a location in the URL or filesystem\n", r);
    ap_rputs("  namespace.\n", r);
    ap_rputs("  </P>\n", r);
    ap_rprintf(r, "  <H2>Static callbacks so far:</H2>\n  <OL>\n%s  </OL>\n",
            trace);
    ap_rputs("  <H2>Request-specific callbacks so far:</H2>\n", r);
    ap_rprintf(r, "  <OL>\n%s  </OL>\n", ap_table_get(r->notes, TRACE_NOTE));
    ap_rputs("  <H2>Environment for <EM>this</EM> call:</H2>\n", r);
    ap_rputs("  <UL>\n", r);
    ap_rprintf(r, "   <LI>Applies-to: <SAMP>%s</SAMP>\n   </LI>\n", dcfg->loc);
    ap_rprintf(r, "   <LI>\"Example\" directive declared here: %s\n   </LI>\n",
            (dcfg->local ? "YES" : "NO"));
    ap_rprintf(r, "   <LI>\"Example\" inherited: %s\n   </LI>\n",
            (dcfg->congenital ? "YES" : "NO"));
    ap_rputs("  </UL>\n", r);
    ap_rputs(" </BODY>\n", r);
    ap_rputs("</HTML>\n", r);
    /*
     * We're all done, so cancel the timeout we set.  Since this is probably
     * the end of the request we *could* assume this would be done during
     * post-processing - but it's possible that another handler might be
     * called and inherit our outstanding timer.  Not good; to each its own.
     */
    ap_kill_timeout(r);
    /*
     * We did what we wanted to do, so tell the rest of the server we
     * succeeded.
     */
    return OK;
}
Exemplo n.º 14
0
int ApacheRequest_parse_multipart(ApacheRequest *req)
{
    request_rec *r = req->r;
    int rc = OK;
    const char *ct = ap_table_get(r->headers_in, "Content-Type");
    long length;
    char *boundary;
    multipart_buffer *mbuff;
    ApacheUpload *upload = NULL;

    if (!ct) {
	ap_log_rerror(REQ_ERROR, "[libapreq] no Content-type header!");
	return HTTP_INTERNAL_SERVER_ERROR;
    }

    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
        return rc;
    }

    if (!ap_should_client_block(r)) {
	return rc;
    }

    if ((length = r->remaining) > req->post_max && req->post_max > 0) {
	ap_log_rerror(REQ_ERROR, "[libapreq] entity too large (%d, max=%d)",
		     (int)length, req->post_max);
	return HTTP_REQUEST_ENTITY_TOO_LARGE;
    }

    (void)ap_getword(r->pool, &ct, '=');
    boundary = ap_getword_conf(r->pool, &ct);

    if (!(mbuff = multipart_buffer_new(boundary, length, r))) {
	return DECLINED;
    }

    while (!multipart_buffer_eof(mbuff)) {
	table *header = multipart_buffer_headers(mbuff);
	const char *cd, *param=NULL, *filename=NULL;
	char buff[FILLUNIT];
	int blen, wlen;

	if (!header) {
#ifdef DEBUG
            ap_log_rerror(REQ_ERROR,
		      "[libapreq] silently drop remaining '%ld' bytes", r->remaining);
#endif
            ap_hard_timeout("[libapreq] parse_multipart", r);
            while ( ap_get_client_block(r, buff, sizeof(buff)) > 0 )
                /* wait for more input to ignore */ ;
            ap_kill_timeout(r);
	    return OK;
	}

	if ((cd = ap_table_get(header, "Content-Disposition"))) {
	    const char *pair;

	    while (*cd && (pair = ap_getword(r->pool, &cd, ';'))) {
		const char *key;

		while (ap_isspace(*cd)) {
		    ++cd;
		}
		if (ap_ind(pair, '=')) {
		    key = ap_getword(r->pool, &pair, '=');
		    if(strEQ(key, "name")) {
			param = ap_getword_conf(r->pool, &pair);
		    }
		    else if(strEQ(key, "filename")) {
			filename = ap_getword_conf(r->pool, &pair);
		    }
		}
	    }
	    if (!filename) {
	        char *value = multipart_buffer_read_body(mbuff);
	        ap_table_add(req->parms, param, value);
		continue;
	    }
	    if (!param) continue; /* shouldn't happen, but just in case. */

            if (req->disable_uploads) {
                ap_log_rerror(REQ_ERROR, "[libapreq] file upload forbidden");
                return HTTP_FORBIDDEN;
            }

	    ap_table_add(req->parms, param, filename);

	    if (upload) {
		upload->next = ApacheUpload_new(req);
		upload = upload->next;
	    }
	    else {
		upload = ApacheUpload_new(req);
		req->upload = upload;
	    }

	    if (! req->upload_hook && ! ApacheRequest_tmpfile(req, upload) ) {
		return HTTP_INTERNAL_SERVER_ERROR;
	    }

	    upload->info = header;
	    upload->filename = ap_pstrdup(req->r->pool, filename);
	    upload->name = ap_pstrdup(req->r->pool, param);

            /* mozilla empty-file (missing CRLF) hack */
            fill_buffer(mbuff);
            if( strEQN(mbuff->buf_begin, mbuff->boundary, 
                      strlen(mbuff->boundary)) ) {
                r->remaining -= 2;
                continue; 
            }

	    while ((blen = multipart_buffer_read(mbuff, buff, sizeof(buff)))) {
		if (req->upload_hook != NULL) {
		    wlen = req->upload_hook(req->hook_data, buff, blen, upload);
		} else {
		    wlen = fwrite(buff, 1, blen, upload->fp);
		}
		if (wlen != blen) {
		    return HTTP_INTERNAL_SERVER_ERROR;
		}
		upload->size += wlen;
	    }

	    if (upload->size > 0 && (upload->fp != NULL)) {
		fseek(upload->fp, 0, 0);
	    }
	}
    }

    return OK;
}
Exemplo n.º 15
0
API_EXPORT(int) ap_scan_script_header_err_core(request_rec *r, char *buffer,
				       int (*getsfunc) (char *, int, void *),
				       void *getsfunc_data)
{
    char x[MAX_STRING_LEN];
    char *w, *l;
    int p;
    int cgi_status = HTTP_OK;
    table *merge;
    table *cookie_table;

    if (buffer) {
	*buffer = '\0';
    }
    w = buffer ? buffer : x;

    ap_hard_timeout("read script header", r);

    /* temporary place to hold headers to merge in later */
    merge = ap_make_table(r->pool, 10);

    /* The HTTP specification says that it is legal to merge duplicate
     * headers into one.  Some browsers that support Cookies don't like
     * merged headers and prefer that each Set-Cookie header is sent
     * separately.  Lets humour those browsers by not merging.
     * Oh what a pain it is.
     */
    cookie_table = ap_make_table(r->pool, 2);
    ap_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL);

    while (1) {

	if ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data) == 0) {
	    ap_kill_timeout(r);
	    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
			  "Premature end of script headers: %s", r->filename);
	    return HTTP_INTERNAL_SERVER_ERROR;
	}

	/* Delete terminal (CR?)LF */

	p = strlen(w);
        /* Indeed, the host's '\n':
           '\012' for UNIX; '\015' for MacOS; '\025' for OS/390
           -- whatever the script generates.
        */
	if (p > 0 && w[p - 1] == '\n') {
	    if (p > 1 && w[p - 2] == CR) {
		w[p - 2] = '\0';
	    }
	    else {
		w[p - 1] = '\0';
	    }
	}

	/*
	 * If we've finished reading the headers, check to make sure any
	 * HTTP/1.1 conditions are met.  If so, we're done; normal processing
	 * will handle the script's output.  If not, just return the error.
	 * The appropriate thing to do would be to send the script process a
	 * SIGPIPE to let it know we're ignoring it, close the channel to the
	 * script process, and *then* return the failed-to-meet-condition
	 * error.  Otherwise we'd be waiting for the script to finish
	 * blithering before telling the client the output was no good.
	 * However, we don't have the information to do that, so we have to
	 * leave it to an upper layer.
	 */
	if (w[0] == '\0') {
	    int cond_status = OK;

	    ap_kill_timeout(r);
	    if ((cgi_status == HTTP_OK) && (r->method_number == M_GET)) {
		cond_status = ap_meets_conditions(r);
	    }
	    ap_overlap_tables(r->err_headers_out, merge,
		AP_OVERLAP_TABLES_MERGE);
	    if (!ap_is_empty_table(cookie_table)) {
		/* the cookies have already been copied to the cookie_table */
		ap_table_unset(r->err_headers_out, "Set-Cookie");
		r->err_headers_out = ap_overlay_tables(r->pool,
		    r->err_headers_out, cookie_table);
	    }
	    return cond_status;
	}

	/* if we see a bogus header don't ignore it. Shout and scream */

#ifdef CHARSET_EBCDIC
	    /* Chances are that we received an ASCII header text instead of
	     * the expected EBCDIC header lines. Try to auto-detect:
	     */
	if (!(l = strchr(w, ':'))) {
	    int maybeASCII = 0, maybeEBCDIC = 0;
	    char *cp;

	    for (cp = w; *cp != '\0'; ++cp) {
		if (isprint(*cp) && !isprint(os_toebcdic[*cp]))
		    ++maybeEBCDIC;
		if (!isprint(*cp) && isprint(os_toebcdic[*cp]))
		    ++maybeASCII;
		}
	    if (maybeASCII > maybeEBCDIC) {
		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
			 "CGI Interface Error: Script headers apparently ASCII: (CGI = %s)", r->filename);
		ascii2ebcdic(w, w, cp - w);
	    }
	}
#endif
	if (!(l = strchr(w, ':'))) {
	    char malformed[(sizeof MALFORMED_MESSAGE) + 1
			   + MALFORMED_HEADER_LENGTH_TO_SHOW];

	    strcpy(malformed, MALFORMED_MESSAGE);
	    strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW);

	    if (!buffer) {
		/* Soak up all the script output - may save an outright kill */
	        while ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data)) {
		    continue;
		}
	    }

	    ap_kill_timeout(r);
	    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
			  "%s: %s", malformed, r->filename);
	    return HTTP_INTERNAL_SERVER_ERROR;
	}

	*l++ = '\0';
	while (*l && ap_isspace(*l)) {
	    ++l;
	}

	if (!strcasecmp(w, "Content-type")) {
	    char *tmp;

	    /* Nuke trailing whitespace */

	    char *endp = l + strlen(l) - 1;
	    while (endp > l && ap_isspace(*endp)) {
		*endp-- = '\0';
	    }

	    tmp = ap_pstrdup(r->pool, l);
	    ap_content_type_tolower(tmp);
	    r->content_type = tmp;
	}
	/*
	 * If the script returned a specific status, that's what
	 * we'll use - otherwise we assume 200 OK.
	 */
	else if (!strcasecmp(w, "Status")) {
	    r->status = cgi_status = atoi(l);
	    r->status_line = ap_pstrdup(r->pool, l);
	}
	else if (!strcasecmp(w, "Location")) {
	    ap_table_set(r->headers_out, w, l);
	}
	else if (!strcasecmp(w, "Content-Length")) {
	    ap_table_set(r->headers_out, w, l);
	}
	else if (!strcasecmp(w, "Transfer-Encoding")) {
	    ap_table_set(r->headers_out, w, l);
	}
	/*
	 * If the script gave us a Last-Modified header, we can't just
	 * pass it on blindly because of restrictions on future values.
	 */
	else if (!strcasecmp(w, "Last-Modified")) {
	    time_t mtime = ap_parseHTTPdate(l);

	    ap_update_mtime(r, mtime);
	    ap_set_last_modified(r);
	}
	else if (!strcasecmp(w, "Set-Cookie")) {
	    ap_table_add(cookie_table, w, l);
	}
	else {
	    ap_table_add(merge, w, l);
	}
    }
}
Exemplo n.º 16
0
static int
ipp_handler(request_rec *r)
{
	papi_attribute_t **request = NULL, **response = NULL;
	IPPListenerConfig *config;
	papi_status_t status;
	int ret;

	/* Really, IPP is all POST requests */
	if (r->method_number != M_POST)
		return (DECLINED);

#ifndef APACHE2
	/*
	 * An IPP request must have a MIME type of "application/ipp"
	 * (RFC-2910, Section 4, page 19).  If it doesn't match this
	 * MIME type, we should decline the request and let someone else
	 * try and handle it.
	 */
	if (r->headers_in != NULL) {
		char *mime_type = (char *)ap_table_get(r->headers_in,
							"Content-Type");

		if ((mime_type == NULL) ||
		    (strcasecmp(mime_type, "application/ipp") != 0))
			return (DECLINED);
	}
#endif
	/* CHUNKED_DECHUNK might not work right for IPP? */
	if ((ret = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK)
		return (ret);

	if (!ap_should_client_block(r))
		return (HTTP_INTERNAL_SERVER_ERROR);

#ifndef APACHE2
	ap_soft_timeout("ipp_module: read/reply request ", r);
#endif
	/* read the IPP request off the network */
	status = ipp_read_message(read_data, r, &request, IPP_TYPE_REQUEST);

	if (status != PAPI_OK)
		_log_rerror(APLOG_MARK, APLOG_ERR, r,
			"read failed: %s\n", papiStatusString(status));
#ifdef DEBUG
	papiAttributeListPrint(stderr, request, "request (%d)  ", getpid());
#endif

	(void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
		"originating-host", (char *)
#ifdef APACHE2
		ap_get_remote_host
			(r->connection, r->per_dir_config, REMOTE_NAME, NULL));
#else
		ap_get_remote_host
			(r->connection, r->per_dir_config, REMOTE_NAME));
#endif

	(void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
				"uri-port", ap_get_server_port(r));
	if (r->headers_in != NULL) {
		char *host = (char *)ap_table_get(r->headers_in, "Host");

		if ((host == NULL) || (host[0] == '\0'))
			host = (char *)ap_get_server_name(r);

		(void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
				"uri-host", host);
	}
	(void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
				"uri-path", r->uri);

	config = ap_get_module_config(r->per_dir_config, &ipp_module);
	if (config != NULL) {
		(void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
				"conformance", config->conformance);
		(void) papiAttributeListAddCollection(&request, PAPI_ATTR_EXCL,
				"operations", config->operations);
		if (config->default_user != NULL)
			(void) papiAttributeListAddString(&request,
						PAPI_ATTR_EXCL, "default-user",
						config->default_user);
		if (config->default_svc != NULL)
			(void) papiAttributeListAddString(&request,
					PAPI_ATTR_EXCL, "default-service",
					config->default_svc);
	}

	/*
	 * For Trusted Solaris, pass the fd number of the socket connection
	 * to the backend so the it can be forwarded to the backend print
	 * service to retrieve the sensativity label off of a multi-level
	 * port.
	 */
	(void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
			"peer-socket", ap_bfileno(r->connection->client, B_RD));

	/* process the request */
	status = ipp_process_request(request, &response, read_data, r);
	if (status != PAPI_OK) {
		errno = 0;
		_log_rerror(APLOG_MARK, APLOG_ERR, r,
			"request failed: %s\n", papiStatusString(status));
		discard_data(r);
	}
#ifdef DEBUG
	fprintf(stderr, "processing result: %s\n", papiStatusString(status));
	papiAttributeListPrint(stderr, response, "response (%d)  ", getpid());
#endif

	/*
	 * If the client is using chunking and we have not yet received the
	 * final "0" sized chunk, we need to discard any data that may
	 * remain in the post request.
	 */
	if ((r->read_chunked != 0) &&
	    (ap_table_get(r->headers_in, "Content-Length") == NULL))
		discard_data(r);

	/* write an IPP response back to the network */
	r->content_type = "application/ipp";

#ifndef	APACHE2
	ap_send_http_header(r);
#endif

	status = ipp_write_message(write_data, r, response);
	if (status != PAPI_OK)
		_log_rerror(APLOG_MARK, APLOG_ERR, r,
			"write failed: %s\n", papiStatusString(status));
#ifdef DEBUG
	fprintf(stderr, "write result: %s\n", papiStatusString(status));
	fflush(stderr);
#endif

	papiAttributeListFree(request);
	papiAttributeListFree(response);

#ifndef APACHE2
	ap_kill_timeout(r);
	if (ap_rflush(r) < 0)
		_log_rerror(APLOG_MARK, APLOG_ERR, r,
			"flush failed, response may not have been sent");
#endif

	return (OK);
}
Exemplo n.º 17
0
static int neko_handler_rec( request_rec *r ) {
	mcontext ctx;
	neko_vm *vm;
	const char *ctype;
	value exc = NULL;

/*
	Seems to crash on Windows. And on Linux, we rarely have libGC 7.x installed anyway

#	if defined(APACHE_2_X) || defined(NEKO_WINDOWS)
	// we are using threads, so let's make sure that the current thread is registered
	neko_thread_register(true);
#	endif
*/

	config.hits++;

	ctx.r = r;
	ctx.main = cache_find(r);
	ctx.post_data = val_null;
	ctx.headers_sent = false;
	ctx.content_type = alloc_string("text/html");
    r->content_type = val_string(ctx.content_type);

	if( ap_setup_client_block(r,REQUEST_CHUNKED_ERROR) != 0 ) {
		send_headers(&ctx);
		apache_error(APLOG_WARNING,r,"ap_setup_client_block failed");
		return OK;
	}

	ctype = ap_table_get(r->headers_in,"Content-Type");
	if( (!ctype || strstr(ctype,"multipart/form-data") == NULL) && ap_should_client_block(r) ) {
#		define MAXLEN 1024
		char buf[MAXLEN];
		int len;
		int tlen = 0;
		buffer b = alloc_buffer(NULL);
		while( (len = ap_get_client_block(r,buf,MAXLEN)) > 0 ) {
			if( tlen < config.max_post_size )
				buffer_append_sub(b,buf,len);
			tlen += len;
		}
		if( tlen >= config.max_post_size ) {
			send_headers(&ctx);
			apache_error(APLOG_WARNING,r,"Maximum POST data exceeded. Try using multipart encoding");
			return OK;
		}
		ctx.post_data = buffer_to_string(b);
	}

	vm = neko_vm_alloc(NULL);
	if( config.use_stats ) neko_vm_set_stats(vm,neko_stats_measure,config.use_prim_stats?neko_stats_measure:NULL);

	neko_vm_set_custom(vm,k_mod_neko,&ctx);
	if( config.use_jit && !neko_vm_jit(vm,1) ) {
		send_headers(&ctx);
		apache_error(APLOG_WARNING,r,"JIT required by env. var but not enabled in NekoVM");
		return OK;
	}

	neko_vm_redirect(vm,request_print,&ctx);
	neko_vm_select(vm);

	if( ctx.main != NULL ) {
		value old = ctx.main;
		if( config.use_stats ) neko_stats_measure(vm,r->filename,1);
		val_callEx(val_null,old,NULL,0,&exc);
		if( config.use_stats ) neko_stats_measure(vm,r->filename,0);
		if( old != ctx.main ) cache_module(r->filename,FTIME(r),ctx.main);
	} else {
		char *base_uri = request_base_uri(r);
		value mload = neko_default_loader(&base_uri,1);
		value args[] = { alloc_string(r->filename), mload };
		char *p = strrchr(val_string(args[0]),'.');
		if( p != NULL )
			*p = 0;
		val_callEx(mload,val_field(mload,val_id("loadmodule")),args,2,&exc);
		if( ctx.main != NULL && config.use_cache )
			cache_module(r->filename,FTIME(r),ctx.main);
	}

	if( exc != NULL ) {
		buffer b = alloc_buffer(NULL);
		value v;
		int i;
		const char *p, *start;
		value st = neko_exc_stack(vm);
		val_buffer(b,exc);
		config.exceptions++;
		ap_soft_timeout("Client Timeout",r);
		send_headers(&ctx);
		v = buffer_to_string(b);
		p = val_string(v);
		start = p;
		ap_rprintf(r,"Uncaught exception - ");
		while( *p ) {
			if( *p == '<' || *p == '>' ) {
				ap_rwrite(start,(int)(p - start),r);
				ap_rwrite((*p == '<')?"&lt;":"&gt;",4, r);
				start = p + 1;
			}
			p++;
		}
		ap_rwrite(start,(int)(p - start),r);
		ap_rprintf(r,"<br/><br/>");
		for(i=0;i<val_array_size(st);i++) {
			value s = val_array_ptr(st)[i];
			if( val_is_null(s) )
				ap_rprintf(r,"Called from a C function<br/>");
			else if( val_is_string(s) ) {
				ap_rprintf(r,"Called from %s (no debug available)<br/>",val_string(s));
			} else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) )
				ap_rprintf(r,"Called from %s line %d<br/>",val_string(val_array_ptr(s)[0]),val_int(val_array_ptr(s)[1]));
			else {
				b = alloc_buffer(NULL);
				val_buffer(b,s);
				ap_rprintf(r,"Called from %s<br/>",val_string(buffer_to_string(b)));
			}
		}
		ap_kill_timeout(r);
		return OK;
	}

	send_headers(&ctx);
    return OK;
}
Exemplo n.º 18
0
static PyObject * req_readline(requestobject *self, PyObject *args)
{

    int rc, chunk_len, bytes_read;
    char *buffer;
    PyObject *result;
    int copied = 0;
    int len = -1;

    if (! PyArg_ParseTuple(args, "|i", &len)) 
	return NULL;

    if (len == 0) {
	return PyString_FromString("");
    }

    /* is this the first read? */
    if (! self->request_rec->read_length) {

	/* then do some initial setting up */
	rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);

	if(rc != OK) {
	    PyObject *val = PyInt_FromLong(rc);
	    if (val == NULL)
		return NULL;
	    PyErr_SetObject(Mp_ServerReturn, val);
	    Py_DECREF(val);
	    return NULL;
	}

	if (! ap_should_client_block(self->request_rec)) {
	    /* client has nothing to send */
	    return PyString_FromString("");
	}
    }

    if (len < 0)
	len = self->request_rec->remaining + 
	    (self->rbuff_len - self->rbuff_pos);

    /* create the result buffer */
    result = PyString_FromStringAndSize(NULL, len);

    /* possibly no more memory */
    if (result == NULL) 
	return NULL;

    buffer = PyString_AS_STRING((PyStringObject *) result);

    /* is there anything left in the rbuff from previous reads? */
    if (self->rbuff_pos < self->rbuff_len) {
	
	/* if yes, process that first */
	while (self->rbuff_pos < self->rbuff_len) {

	    buffer[copied++] = self->rbuff[self->rbuff_pos];
	    if ((self->rbuff[self->rbuff_pos++] == '\n') || 
		(copied == len)) {

		/* our work is done */

		/* resize if necessary */
		if (copied < len) 
		    if(_PyString_Resize(&result, copied))
			return NULL;

		return result;
	    }
	}
    }

    /* if got this far, the buffer should be empty, we need to read more */
	
    /* create a read buffer */
    self->rbuff_len = len > HUGE_STRING_LEN ? len : HUGE_STRING_LEN;
    self->rbuff_pos = self->rbuff_len;
    self->rbuff = ap_palloc(self->request_rec->pool, self->rbuff_len);
    if (! self->rbuff)
	return PyErr_NoMemory();

    /* set timeout */
    ap_soft_timeout("mod_python_read", self->request_rec);

    /* read it in */
    Py_BEGIN_ALLOW_THREADS
	chunk_len = ap_get_client_block(self->request_rec, self->rbuff, 
					self->rbuff_len);
    Py_END_ALLOW_THREADS;
    bytes_read = chunk_len;

    /* if this is a "short read", try reading more */
    while ((chunk_len != 0 ) && (bytes_read + copied < len)) {
	Py_BEGIN_ALLOW_THREADS
	    chunk_len = ap_get_client_block(self->request_rec, 
					    self->rbuff + bytes_read, 
					    self->rbuff_len - bytes_read);
	Py_END_ALLOW_THREADS
	    ap_reset_timeout(self->request_rec);
	if (chunk_len == -1) {
	    ap_kill_timeout(self->request_rec);
	    PyErr_SetObject(PyExc_IOError, 
			    PyString_FromString("Client read error (Timeout?)"));
	    return NULL;
	}
	else
	    bytes_read += chunk_len;
    }
    self->rbuff_len = bytes_read;
    self->rbuff_pos = 0;
    ap_kill_timeout(self->request_rec);

    /* now copy the remaining bytes */
    while (self->rbuff_pos < self->rbuff_len) {

	buffer[copied++] = self->rbuff[self->rbuff_pos];
	if ((self->rbuff[self->rbuff_pos++] == '\n') || 
	    (copied == len)) 
	    /* our work is done */
	    break;
    }

    /* resize if necessary */
    if (copied < len) 
	if(_PyString_Resize(&result, copied))
	    return NULL;

    return result;
}
Exemplo n.º 19
0
/*
 *	ic_send_request()
 *	-----------------
 *	Send the client's page/form request to the Interchange server
 */
static int ic_send_request(request_rec *r,ic_conf_rec *conf_rec,BUFF *ic_buff)
{
	char **env,**e,*rp;
	int env_count,rc;
	char request_uri[MAX_STRING_LEN];
	char redirect_url[MAX_STRING_LEN];

	/*
	 *	send the Interchange-link arg parameter
	 *	(this is always empty for a CGI request)
	 */
	ap_hard_timeout("ic_send_request",r);
	if (ap_bputs("arg 0\n",ic_buff) < 0){
		ap_log_reason("error writing to Interchange",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	ap_reset_timeout(r);

	/*
	 *	initialize the environment to send to Interchange
	 */
	ap_add_common_vars(r);
	ap_add_cgi_vars(r);
	env = ap_create_environment(r->pool,r->subprocess_env);

	/*
	 *	count the number of environment variables present
	 */
	for (e = env,env_count = 0; *e != NULL; e++,env_count++){
		if (strncmp(*e,"PATH_INFO=",10) == 0)
			env_count--;
	}
	env_count++;

	/*
	 *	send the environment variable count to Interchange
	 */
	if (ap_bprintf(ic_buff,"env %d\n",env_count) < 0){
		ap_log_reason("error writing to Interchange",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	ap_reset_timeout(r);

	/*
	 *	ignore the PATH_INFO variable and fix the SCRIPT_NAME,
	 *	REQUEST_URI and REDIRECT_URL variable content
	 */
	request_uri[0] = '\0';
	redirect_url[0] = '\0';
	for (e = env; *e != NULL; e++){
		int len;
		char tmp[MAX_STRING_LEN];
		char *p = *e;

		if (strncmp(p,"PATH_INFO=",10) == 0)
			continue;
		if (strncmp(p,"REDIRECT_URL=",13) == 0){
			strncpy(redirect_url,p + 13,MAX_STRING_LEN - 14);
			continue;
		}
		if (strncmp(p,"REQUEST_URI=",12) == 0)
			strncpy(request_uri,p + 12,MAX_STRING_LEN - 13);
		else if (strncmp(p,"SCRIPT_NAME=",12) == 0){
			p = tmp;
			strcpy(p,"SCRIPT_NAME=");

			if (conf_rec->script_name[0])
				strcat(p,conf_rec->script_name);
			else{
				strcat(p,"/");
				strcat(p,conf_rec->location);
			}
		}
		len = strlen(p);
		if (len && ap_bprintf(ic_buff,"%d %s\n",len,p) < 0){
			ap_log_reason("error writing to Interchange",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}

	rp = request_uri;

	while (*rp == '/')
		rp++;

	/*
	 *	strip the location path from the request_uri string
	 *	unless the location is "/"
	 */
	if (conf_rec->location[0] != '\0'){
		if (strncmp(rp,conf_rec->location,conf_rec->location_len) == 0)
			rp += conf_rec->location_len;
	}else{
		if (rp != request_uri)
			rp--;
	}

	strncpy(request_uri,rp,MAX_STRING_LEN - 1);
	request_uri[MAX_STRING_LEN - 1] = '\0';

	for (rp = request_uri; *rp != '\0'; rp++){
		if (*rp == '?'){
			*rp = '\0';
			break;
		}
	}
	switch (ap_unescape_url(request_uri)){
	case BAD_REQUEST:
	case NOT_FOUND:
		ap_log_reason("Bad URI entities found",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	/*
	 *	send the PATH_INFO variable as our "fixed" REQUEST_URI
	 */
	if (ap_bprintf(ic_buff,"%d PATH_INFO=%s\n",strlen(request_uri) + 10,request_uri) < 0){
		ap_log_reason("error writing to Interchange",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	/*
	 *	check if we have a REDIRECT_URL
	 *	if so then give it the same "fixes" as PATH_INFO (REQUEST_URI)
	 */
	if (redirect_url[0] != '\0'){
		rp = redirect_url;

		while (*rp == '/')
			rp++;

		/*
		 *	strip the location path from the request_uri string
		 *	unless the location is "/"
		 */
		if (conf_rec->location[0] != '\0'){
			if (strncmp(rp,conf_rec->location,conf_rec->location_len) == 0)
				rp += conf_rec->location_len;
		}else{
			if (rp != redirect_url)
				rp--;
		}

		strncpy(redirect_url,rp,MAX_STRING_LEN - 1);
		redirect_url[MAX_STRING_LEN - 1] = '\0';

		for (rp = redirect_url; *rp != '\0'; rp++){
			if (*rp == '?'){
				*rp = '\0';
				break;
			}
		}
		switch (ap_unescape_url(redirect_url)){
		case BAD_REQUEST:
		case NOT_FOUND:
			ap_log_reason("Bad URI entities found",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}

		if (ap_bprintf(ic_buff,"%d REDIRECT_URL=%s\n",strlen(redirect_url) + 13,redirect_url) < 0){
			ap_log_reason("error writing to Interchange",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}
	ap_reset_timeout(r);

	/*
	 *	send the request body, if any
	 */
	if (ap_should_client_block(r)){
		char buffer[MAX_STRING_LEN];
		int len_read;
		long length = r->remaining;

		if (ap_bprintf(ic_buff,"entity\n%ld ",length) < 0){
			ap_log_reason("error writing to Interchange",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}

		/*
		 *	read a block of data from the client and send
		 *	it to the Interchange server, until there
		 *	is nothing more to read from the client
		 */
		while ((len_read = ap_get_client_block(r,buffer,sizeof(buffer))) > 0){
			ap_reset_timeout(r);

			if (ap_bwrite(ic_buff,buffer,len_read) != len_read){
				ap_log_reason("error writing client block to Interchange",r->uri,r);
				return HTTP_INTERNAL_SERVER_ERROR;
			}
			ap_reset_timeout(r);
		}
		if (len_read < 0){
			ap_log_reason("error reading block from client",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}

		/*
		 *	send an end of line character to Interchange
		 */
		if (ap_bputc('\n',ic_buff) < 0){
			ap_log_reason("error writing to Interchange",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}

	/*
	 *	all data has been sent, so send the "end" marker
	 */
	ap_reset_timeout(r);
	if (ap_bputs("end\n",ic_buff) < 0){
		ap_log_reason("error writing the end marker to Interchange",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	if (ap_bflush(ic_buff) < 0){
		ap_log_reason("error flushing data to Interchange",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	ap_kill_timeout(r);
	return OK;
}
Exemplo n.º 20
0
/*
 * This handles http:// URLs, and other URLs using a remote proxy over http
 * If proxyhost is NULL, then contact the server directly, otherwise
 * go via the proxy.
 * Note that if a proxy is used, then URLs other than http: can be accessed,
 * also, if we have trouble which is clearly specific to the proxy, then
 * we return DECLINED so that we can try another proxy. (Or the direct
 * route.)
 */
int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
                              const char *proxyhost, int proxyport)
{
    const char *strp;
    char *strp2;
    const char *err, *desthost;
    int i, j, sock,/* len,*/ backasswards;
    table *req_hdrs, *resp_hdrs;
    array_header *reqhdrs_arr;
    table_entry *reqhdrs_elts;
    BUFF *f;
    char buffer[HUGE_STRING_LEN];
    char portstr[32];
    pool *p = r->pool;
    int chunked = 0, destport = 0;
    char *destportstr = NULL;
    const char *urlptr = NULL;
    const char *datestr, *urlstr;
    struct addrinfo hints, *res, *res0;
    int error;
    int result, major, minor;
    const char *content_length;
    const char *peer;
    int destportstrtonum;
    const char *errstr;

    void *sconf = r->server->module_config;
    proxy_server_conf *conf =
    (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);
    struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
    struct nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts;
    int nocache = 0;

    if (conf->cache.root == NULL)
        nocache = 1;

    /* We break the URL into host, port, path-search */

    urlptr = strstr(url, "://");
    if (urlptr == NULL)
        return HTTP_BAD_REQUEST;
    destport = DEFAULT_HTTP_PORT;
    urlptr += 3;
    ap_hook_use("ap::mod_proxy::http::handler::set_destport", 
                AP_HOOK_SIG2(int,ptr), 
                AP_HOOK_TOPMOST,
                &destport, r);
    ap_snprintf(portstr, sizeof(portstr), "%d", destport);
    destportstr = portstr;
    strp = strchr(urlptr, '/');
    if (strp == NULL) {
        desthost = ap_pstrdup(p, urlptr);
        urlptr = "/";
    }
    else {
        char *q = ap_palloc(p, strp - urlptr + 1);
        memcpy(q, urlptr, strp - urlptr);
        q[strp - urlptr] = '\0';
        urlptr = strp;
        desthost = q;
    }
    if (*desthost == '['){
      char *u = strrchr(desthost+1, ']');
      if (u){
          desthost++;
          *u = '\0';
          if (*(u+1) == ':'){ /* [host]:xx */
              strp2 = u+1;
          }
          else if (*(u+1) == '\0'){   /* [host] */
              strp2 = NULL;
          }
          else
              return HTTP_BAD_REQUEST;
      }
      else
          return HTTP_BAD_REQUEST;
    }
    else
       strp2 = strrchr(desthost, ':');

    if (strp2 != NULL) {
        *(strp2++) = '\0';
        if (ap_isdigit(*strp2))
            destportstr = strp2;
    }

    /* Make sure peer is always set to prevent a segfault in the SSL handler */
    peer = desthost;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    error = getaddrinfo(desthost, destportstr, &hints, &res0);
    if (error && proxyhost == NULL) {
      return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
                  gai_strerror(error));       /* give up */
     }
 
      /* check if ProxyBlock directive on this host */
      for (i = 0; i < conf->noproxies->nelts; i++) {
      int fail;
      struct sockaddr_in *sin;

      fail = 0;
      if (npent[i].name != NULL && strstr(desthost, npent[i].name))
          fail++;
      if (npent[i].name != NULL && strcmp(npent[i].name, "*") == 0)
          fail++;
      for (res = res0; res; res = res->ai_next) {
          switch (res->ai_family) {
          case AF_INET:
              sin = (struct sockaddr_in *)res->ai_addr;
              if (sin->sin_addr.s_addr == npent[i].addr.s_addr)
                  fail++;
              break;
		
          }
      }
      if (fail) {
          if (res0 != NULL)
              freeaddrinfo(res0);
          return ap_proxyerror(r, HTTP_FORBIDDEN,
                               "Connect to remote machine blocked");
      }
    }
    if (proxyhost != NULL) {
      char pbuf[10];

      if (res0 != NULL)
          freeaddrinfo(res0);

      ap_snprintf(pbuf, sizeof(pbuf), "%d", proxyport);
      memset(&hints, 0, sizeof(hints));
      hints.ai_family = PF_UNSPEC;
      hints.ai_socktype = SOCK_STREAM;
      hints.ai_protocol = IPPROTO_TCP;
      error = getaddrinfo(proxyhost, pbuf, &hints, &res0);
      if (error)
          return DECLINED;    /* try another */
    }

    /* check if ProxyBlock directive on this host */
    for (i = 0; i < conf->noproxies->nelts; i++) {
	peer =  ap_psprintf(p, "%s:%s", desthost, destportstr);  
    }


    /*
     * we have worked out who exactly we are going to connect to, now make
     * that connection...
     */
     sock = i = -1;
     for (res = res0; res; res = res->ai_next) {
       sock = ap_psocket(p, res->ai_family, res->ai_socktype,
           res->ai_protocol);
       if (sock < 0)
           continue;

      if (conf->recv_buffer_size) {
          if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
                         (const char *)&conf->recv_buffer_size, sizeof(int))
              == -1) {
              ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
                            "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
          }
      }

      i = ap_proxy_doconnect(sock, res->ai_addr, r);
      if (i == 0)
          break;
      ap_pclosesocket(p, sock);
    }
    freeaddrinfo(res0);

    if (i == -1) {
        if (proxyhost != NULL)
            return DECLINED;    /* try again another way */
        else
            return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
                                    "Could not connect to remote machine: ",
                                                    strerror(errno), NULL));
    }

    /* record request_time for HTTP/1.1 age calculation */
    c->req_time = time(NULL);

    /*
     * build upstream-request headers by stripping r->headers_in from
     * connection specific headers. We must not remove the Connection: header
     * from r->headers_in, we still have to react to Connection: close
     */
    req_hdrs = ap_copy_table(r->pool, r->headers_in);
    ap_proxy_clear_connection(r->pool, req_hdrs);

    /*
     * At this point, we start sending the HTTP/1.1 request to the remote
     * server (proxy or otherwise).
     */
    f = ap_bcreate(p, B_RDWR | B_SOCKET);
    ap_bpushfd(f, sock, sock);

    {
        char *errmsg = NULL;
        ap_hook_use("ap::mod_proxy::http::handler::new_connection", 
                    AP_HOOK_SIG4(ptr,ptr,ptr,ptr), 
                    AP_HOOK_DECLINE(NULL),
                    &errmsg, r, f, peer);
        if (errmsg != NULL)
            return ap_proxyerror(r, HTTP_BAD_GATEWAY, errmsg);
    }

    ap_hard_timeout("proxy send", r);
    ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.1" CRLF,
              NULL);
    {
	int rc = DECLINED;
	ap_hook_use("ap::mod_proxy::http::handler::write_host_header", 
		    AP_HOOK_SIG6(int,ptr,ptr,ptr,ptr,ptr), 
		    AP_HOOK_DECLINE(DECLINED),
		    &rc, r, f, desthost, destportstr, destportstr);
        if (rc == DECLINED) {
	    destportstrtonum = strtonum(destportstr, 0, 65535, &errstr);
	    if (errstr)
		errx(1, "The destination port is %s: %s", errstr, destportstr);

	    if (destportstr != NULL && destportstrtonum != destport)
		ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
	    else
		ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
        }
    }

    if (conf->viaopt == via_block) {
        /* Block all outgoing Via: headers */
        ap_table_unset(req_hdrs, "Via");
    }
    else if (conf->viaopt != via_off) {
        /* Create a "Via:" request header entry and merge it */
        i = ap_get_server_port(r);
        if (ap_is_default_port(i, r)) {
            strlcpy(portstr, "", sizeof(portstr));
        }
        else {
            ap_snprintf(portstr, sizeof portstr, ":%d", i);
        }
        /* Generate outgoing Via: header with/without server comment: */
        ap_table_mergen(req_hdrs, "Via",
                        (conf->viaopt == via_full)
                        ? ap_psprintf(p, "%d.%d %s%s (%s)",
                                      HTTP_VERSION_MAJOR(r->proto_num),
                                      HTTP_VERSION_MINOR(r->proto_num),
                                      ap_get_server_name(r), portstr,
                                      SERVER_BASEVERSION)
                        : ap_psprintf(p, "%d.%d %s%s",
                                      HTTP_VERSION_MAJOR(r->proto_num),
                                      HTTP_VERSION_MINOR(r->proto_num),
                                      ap_get_server_name(r), portstr)
            );
    }

    /* the X-* headers are only added if we are a reverse
     * proxy, otherwise we would be giving away private information.
     */
    if (r->proxyreq == PROXY_PASS) {
        const char *buf;

        /*
         * Add X-Forwarded-For: so that the upstream has a chance to determine,
         * where the original request came from.
         */
        ap_table_mergen(req_hdrs, "X-Forwarded-For", r->connection->remote_ip);

        /* Add X-Forwarded-Host: so that upstream knows what the
         * original request hostname was.
         */
        if ((buf = ap_table_get(r->headers_in, "Host"))) {
            ap_table_mergen(req_hdrs, "X-Forwarded-Host", buf);
        }

        /* Add X-Forwarded-Server: so that upstream knows what the
         * name of this proxy server is (if there are more than one)
         * XXX: This duplicates Via: - do we strictly need it?
         */
        ap_table_mergen(req_hdrs, "X-Forwarded-Server", r->server->server_hostname);
    } 

    /* we don't yet support keepalives - but we will soon, I promise! */
    ap_table_set(req_hdrs, "Connection", "close");

    reqhdrs_arr = ap_table_elts(req_hdrs);
    reqhdrs_elts = (table_entry *)reqhdrs_arr->elts;
    for (i = 0; i < reqhdrs_arr->nelts; i++) {
        if (reqhdrs_elts[i].key == NULL || reqhdrs_elts[i].val == NULL

        /*
         * Clear out hop-by-hop request headers not to send: RFC2616 13.5.1
         * says we should strip these headers:
         */
            || !strcasecmp(reqhdrs_elts[i].key, "Host") /* Already sent */
            || !strcasecmp(reqhdrs_elts[i].key, "Keep-Alive")
            || !strcasecmp(reqhdrs_elts[i].key, "TE")
            || !strcasecmp(reqhdrs_elts[i].key, "Trailer")
            || !strcasecmp(reqhdrs_elts[i].key, "Transfer-Encoding")
            || !strcasecmp(reqhdrs_elts[i].key, "Upgrade")
        /*
         * XXX: @@@ FIXME: "Proxy-Authorization" should *only* be suppressed
         * if THIS server requested the authentication, not when a frontend
         * proxy requested it!
         * 
         * The solution to this problem is probably to strip out the
         * Proxy-Authorisation header in the authorisation code itself, not
         * here. This saves us having to signal somehow whether this request
         * was authenticated or not.
         */
            || !strcasecmp(reqhdrs_elts[i].key, "Proxy-Authorization"))
            continue;
        ap_bvputs(f, reqhdrs_elts[i].key, ": ", reqhdrs_elts[i].val, CRLF, NULL);
    }

    /* the obligatory empty line to mark the end of the headers */
    ap_bputs(CRLF, f);

    /* and flush the above away */
    ap_bflush(f);

    /* and kill the send timeout */
    ap_kill_timeout(r);


    /* read the request data, and pass it to the backend.
     * we might encounter a stray 100-continue reponse from a PUT or POST,
     * if this happens we ignore the 100 continue status line and read the
     * response again.
     */
    {
        /* send the request data, if any. */
        ap_hard_timeout("proxy receive request data", r);
        if (ap_should_client_block(r)) {
            while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0) {
                ap_reset_timeout(r);
                ap_bwrite(f, buffer, i);
            }
        }
        ap_bflush(f);
        ap_kill_timeout(r);


        /* then, read a response line */
        ap_hard_timeout("proxy receive response status line", r);
        result = ap_proxy_read_response_line(f, r, buffer, sizeof(buffer)-1, &backasswards, &major, &minor);
        ap_kill_timeout(r);

        /* trap any errors */
        if (result != OK) {
            ap_bclose(f);
            return result;
        }

        /* if this response was 100-continue, a stray response has been caught.
         * read the line again for the real response
         */
        if (r->status == 100) {
            ap_hard_timeout("proxy receive response status line", r);
            result = ap_proxy_read_response_line(f, r, buffer, sizeof(buffer)-1, &backasswards, &major, &minor);
            ap_kill_timeout(r);

            /* trap any errors */
            if (result != OK) {
                ap_bclose(f);
                return result;
            }
        }
    }


    /*
     * We have our response status line from the convoluted code above,
     * now we read the headers to continue.
     */
    ap_hard_timeout("proxy receive response headers", r);

    /*
     * Is it an HTTP/1 response? Do some sanity checks on the response. (This
     * is buggy if we ever see an HTTP/1.10)
     */
    if (backasswards == 0) {

        /* read the response headers. */
        /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */
        /* Also, take care with headers with multiple occurences. */

        resp_hdrs = ap_proxy_read_headers(r, buffer, sizeof(buffer), f);
        if (resp_hdrs == NULL) {
            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, r->server,
                         "proxy: Bad HTTP/%d.%d header returned by %s (%s)",
                         major, minor, r->uri, r->method);
            resp_hdrs = ap_make_table(p, 20);
            nocache = 1;        /* do not cache this broken file */
        }

        /* handle Via header in the response */
        if (conf->viaopt != via_off && conf->viaopt != via_block) {
            /* Create a "Via:" response header entry and merge it */
            i = ap_get_server_port(r);
            if (ap_is_default_port(i, r)) {
                strlcpy(portstr, "", sizeof(portstr));
            }
            else {
                ap_snprintf(portstr, sizeof portstr, ":%d", i);
            }
            ap_table_mergen((table *)resp_hdrs, "Via",
                            (conf->viaopt == via_full)
                            ? ap_psprintf(p, "%d.%d %s%s (%s)",
                                          major, minor,
                                          ap_get_server_name(r), portstr,
                                          SERVER_BASEVERSION)
                            : ap_psprintf(p, "%d.%d %s%s",
                                          major, minor,
                                          ap_get_server_name(r), portstr)
                );
        }

        /* is this content chunked? */
        chunked = ap_find_last_token(r->pool,
                                     ap_table_get(resp_hdrs, "Transfer-Encoding"),
                                     "chunked");

        /* strip hop-by-hop headers defined by Connection and RFC2616 */
        ap_proxy_clear_connection(p, resp_hdrs);

        content_length = ap_table_get(resp_hdrs, "Content-Length");
        if (content_length != NULL) {
            c->len = ap_strtol(content_length, NULL, 10);

	    if (c->len < 0) {
		ap_kill_timeout(r);
		return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
				     "Invalid Content-Length from remote server",
                                      NULL));
	    }
        }

    }
    else {
        /* an http/0.9 response */

        /* no headers */
        resp_hdrs = ap_make_table(p, 20);
    }

    ap_kill_timeout(r);

    /*
     * HTTP/1.1 requires us to accept 3 types of dates, but only generate one
     * type
     */
    /*
     * we SET the dates here, obliterating possible multiple dates, as only
     * one of each date makes sense in each response.
     */
    if ((datestr = ap_table_get(resp_hdrs, "Date")) != NULL)
        ap_table_set(resp_hdrs, "Date", ap_proxy_date_canon(p, datestr));
    if ((datestr = ap_table_get(resp_hdrs, "Last-Modified")) != NULL)
        ap_table_set(resp_hdrs, "Last-Modified", ap_proxy_date_canon(p, datestr));
    if ((datestr = ap_table_get(resp_hdrs, "Expires")) != NULL)
        ap_table_set(resp_hdrs, "Expires", ap_proxy_date_canon(p, datestr));

    /* handle the ProxyPassReverse mappings */
    if ((urlstr = ap_table_get(resp_hdrs, "Location")) != NULL)
        ap_table_set(resp_hdrs, "Location", proxy_location_reverse_map(r, urlstr));
    if ((urlstr = ap_table_get(resp_hdrs, "URI")) != NULL)
        ap_table_set(resp_hdrs, "URI", proxy_location_reverse_map(r, urlstr));
    if ((urlstr = ap_table_get(resp_hdrs, "Content-Location")) != NULL)
        ap_table_set(resp_hdrs, "Content-Location", proxy_location_reverse_map(r, urlstr));

/* check if NoCache directive on this host */
  {
    struct sockaddr_in *sin;
    struct sockaddr_in6 *sin6;

    if (nocache == 0) {
	for (i = 0; i < conf->nocaches->nelts; i++) {
	    if (ncent[i].name != NULL && 
		(ncent[i].name[0] == '*' ||
		 strstr(desthost, ncent[i].name) != NULL)) {
		nocache = 1;
		break;
	    }
	    switch (res->ai_addr->sa_family) {
	    case AF_INET:
		sin = (struct sockaddr_in *)res->ai_addr;
		if (sin->sin_addr.s_addr == ncent[i].addr.s_addr) {
		    nocache = 1;
		    break;
		}
	    }
	}

        /* update the cache file, possibly even fulfilling the request if
         * it turns out a conditional allowed us to serve the object from the
         * cache...
         */
        i = ap_proxy_cache_update(c, resp_hdrs, !backasswards, nocache);
        if (i != DECLINED) {
            ap_bclose(f);
            return i;
        }

        /* write status line and headers to the cache file */
        ap_proxy_write_headers(c, ap_pstrcat(p, "HTTP/1.1 ", r->status_line, NULL), resp_hdrs);
    }
  }

    /* Setup the headers for our client from upstreams response-headers */
    ap_proxy_table_replace(r->headers_out, resp_hdrs);
    /* Add X-Cache header - be careful not to obliterate any upstream headers */
    ap_table_mergen(r->headers_out, "X-Cache",
                    ap_pstrcat(r->pool, "MISS from ",
                               ap_get_server_name(r), NULL));
    /* The Content-Type of this response is the upstream one. */
    r->content_type = ap_table_get(r->headers_out, "Content-Type");
    ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "Content-Type: %s", r->content_type);

    /* finally output the headers to the client */
    ap_send_http_header(r);

    /*
     * Is it an HTTP/0.9 respose? If so, send the extra data we read from
     * upstream as the start of the reponse to client
     */
/* FIXME: This code is broken: we try and write a buffer and length that
 * were never intelligently initialised. Rather have a bit of broken protocol
 * handling for now than broken code.
 */
/*
    if (backasswards) {
        ap_hard_timeout("proxy send assbackward", r);

        ap_bwrite(r->connection->client, buffer, len);
        if (c != NULL && c->fp != NULL && ap_bwrite(c->fp, buffer, len) != len) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
                      "proxy: error writing extra data to %s", c->tempfile);
            c = ap_proxy_cache_error(c);
        }
        ap_kill_timeout(r);
    }
*/

/* send body */
/* if header only, then cache will be NULL */
/* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
/* XXX CHANGEME: We want to eventually support keepalives, which means
 * we must read content-length bytes... */
    if (!r->header_only) {
/* we need to set this for ap_proxy_send_fb()... */
        c->cache_completion = conf->cache.cache_completion;

/* XXX CHECKME: c->len should be the expected content length, or -1 if the
 * content length is not known. We need to make 100% sure c->len is always
 * set correctly before we get here to correctly do keepalive.
 */
        ap_proxy_send_fb(f, r, c, c->len, 0, chunked, conf->io_buffer_size);
    }

    /* ap_proxy_send_fb() closes the socket f for us */

    ap_proxy_cache_tidy(c);

    ap_proxy_garbage_coll(r);
    return OK;
}