/* * 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; }
/** * 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; }
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; }
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); }
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; }
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; }
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; }
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; }
/* ==================================================================== * 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; }
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; }
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; }
/* * 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; }
/* * 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><routine-name>", r); ap_rputs("(<routine-data>)</SAMP>\n", r); ap_rputs(" </DT>\n", r); ap_rputs(" <DD><SAMP>[<applies-to>]</SAMP>\n", r); ap_rputs(" </DD>\n", r); ap_rputs(" </DL>\n", r); ap_rputs(" <P>\n", r); ap_rputs(" The <SAMP><routine-data></SAMP> is supplied by\n", r); ap_rputs(" the routine when it requests the trace,\n", r); ap_rputs(" and the <SAMP><applies-to></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; }
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; }
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); } } }
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); }
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 == '<')?"<":">",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; }
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; }
/* * 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; }
/* * 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; }