/* * Internal redirect / subrequest handler, working on request_status hook */ static int scgi_request_status(int *status, request_rec *r) { scgi_request_config *req_conf; if ( (*status == OK) && (req_conf = ap_get_module_config(r->request_config, &proxy_scgi_module))) { switch (req_conf->type) { case scgi_internal_redirect: ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "proxy: " PROXY_FUNCTION ": Internal redirect to %s", req_conf->location); r->status_line = NULL; if (r->method_number != M_GET) { /* keep HEAD, which is passed around as M_GET, too */ r->method = "GET"; r->method_number = M_GET; } apr_table_unset(r->headers_in, "Content-Length"); ap_internal_redirect_handler(req_conf->location, r); return OK; /* break; */ case scgi_sendfile: ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "proxy: " PROXY_FUNCTION ": File subrequest to %s", req_conf->location); do { request_rec *rr; rr = ap_sub_req_lookup_file(req_conf->location, r, r->output_filters); if (rr->status == HTTP_OK && rr->finfo.filetype != 0) { /* * We don't touch Content-Length here. It might be * borked (there's plenty of room for a race condition). * Either the backend sets it or it's gonna be chunked. */ ap_run_sub_req(rr); } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Subrequest to file '%s' not possible. " "(rr->status=%d, rr->finfo.filetype=%d)", req_conf->location, rr->status, rr->finfo.filetype); *status = HTTP_INTERNAL_SERVER_ERROR; return *status; } } while(0); return OK; /* break; */ } } return DECLINED; }
static int req_internal_redirect_handle(lua_State* L) { request_rec *r = CHECK_REQUEST_OBJECT(1); const char *new_uri = luaL_optstring(L, 2, r->uri); ap_internal_redirect_handler(new_uri, r); return 0; }
CAMLprim value netcgi2_apache_request_internal_redirect_handler (value new_uri, value rv) { CAMLparam2 (new_uri, rv); request_rec *r = Request_rec_val (rv); ap_internal_redirect_handler (String_val (new_uri), r); CAMLreturn (Val_unit); }
static int asis_handler(request_rec *r) { FILE *f; const char *location; r->allowed |= (1 << M_GET); if (r->method_number != M_GET) return DECLINED; if (r->finfo.st_mode == 0) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "File does not exist: %s", r->filename); return NOT_FOUND; } f = ap_pfopen(r->pool, r->filename, "r"); if (f == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "file permissions deny server access: %s", r->filename); return FORBIDDEN; } ap_scan_script_header_err(r, f, NULL); location = ap_table_get(r->headers_out, "Location"); if (location && location[0] == '/' && ((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) { ap_pfclose(r->pool, f); /* Internal redirect -- fake-up a pseudo-request */ r->status = HTTP_OK; /* This redirect needs to be a GET no matter what the original * method was. */ r->method = ap_pstrdup(r->pool, "GET"); r->method_number = M_GET; ap_internal_redirect_handler(location, r); return OK; } ap_send_http_header(r); if (!r->header_only) ap_send_fd(f, r); ap_pfclose(r->pool, f); return OK; }
/* The sample content handler */ static int maff_handler(request_rec *r) { if (strcmp(r->handler, "maff")) { return DECLINED; } char buf2[1024]; if (doesAccept(r)) { if (strcmp(r->content_type, "text/html") == 0) { sprintf(buf2, "%s.maff", r->filename); if (file_exists(buf2)) { sprintf(buf2, "%s.maff", r->uri); ap_internal_redirect_handler(buf2, r); return OK; } } } return OK; }
static int asis_handler(request_rec *r) { conn_rec *c = r->connection; apr_file_t *f = NULL; apr_status_t rv; const char *location; if(strcmp(r->handler,ASIS_MAGIC_TYPE) && strcmp(r->handler,"send-as-is")) return DECLINED; r->allowed |= (AP_METHOD_BIT << M_GET); if (r->method_number != M_GET) return DECLINED; if (r->finfo.filetype == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "File does not exist: %s", r->filename); return HTTP_NOT_FOUND; } if ((rv = apr_file_open(&f, r->filename, APR_READ, APR_OS_DEFAULT, r->pool)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "file permissions deny server access: %s", r->filename); return HTTP_FORBIDDEN; } ap_scan_script_header_err(r, f, NULL); location = apr_table_get(r->headers_out, "Location"); if (location && location[0] == '/' && ((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) { apr_file_close(f); /* Internal redirect -- fake-up a pseudo-request */ r->status = HTTP_OK; /* This redirect needs to be a GET no matter what the original * method was. */ r->method = apr_pstrdup(r->pool, "GET"); r->method_number = M_GET; ap_internal_redirect_handler(location, r); return OK; } if (!r->header_only) { apr_bucket_brigade *bb; apr_bucket *b; apr_off_t pos = 0; rv = apr_file_seek(f, APR_CUR, &pos); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "mod_asis: failed to find end-of-headers position " "for %s", r->filename); apr_file_close(f); return HTTP_INTERNAL_SERVER_ERROR; } bb = apr_brigade_create(r->pool, c->bucket_alloc); #if APR_HAS_LARGE_FILES if (r->finfo.size - pos > AP_MAX_SENDFILE) { /* APR_HAS_LARGE_FILES issue; must split into mutiple buckets, * no greater than MAX(apr_size_t), and more granular than that * in case the brigade code/filters attempt to read it directly. */ apr_off_t fsize = r->finfo.size - pos; b = apr_bucket_file_create(f, pos, AP_MAX_SENDFILE, r->pool, c->bucket_alloc); while (fsize > AP_MAX_SENDFILE) { APR_BRIGADE_INSERT_TAIL(bb, b); apr_bucket_copy(b, &b); b->start += AP_MAX_SENDFILE; fsize -= AP_MAX_SENDFILE; } b->length = (apr_size_t)fsize; /* Resize just the last bucket */ } else #endif b = apr_bucket_file_create(f, pos, (apr_size_t) (r->finfo.size - pos), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(r->output_filters, bb); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "mod_asis: ap_pass_brigade failed for file %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } } else { apr_file_close(f); } return OK; }
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; }
/* copied from mod_cgi.c and slightly modified * to work with fcgi_record types */ static int fcgi_server_parse_headers(fcgi_request_t *fr, uint16_t request_id, char **data) { request_rec *r = fr->r; int ret, termarg; if ((ret = ap_scan_script_header_err_strs(r, NULL, (const char **)data, &termarg, *data, NULL))) { /* * ret could be HTTP_NOT_MODIFIED in the case that the CGI script * does not set an explicit status and ap_meets_conditions, which * is called by ap_scan_script_header_err_brigade, detects that * the conditions of the requests are met and the response is * not modified. * In this case set r->status and return OK in order to prevent * running through the error processing stack as this would * break with mod_cache, if the conditions had been set by * mod_cache itself to validate a stale entity. * BTW: We circumvent the error processing stack anyway if the * CGI script set an explicit status code (whatever it is) and * the only possible values for ret here are: * * HTTP_NOT_MODIFIED (set by ap_meets_conditions) * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the * processing of the response of the CGI script, e.g broken headers * or a crashed CGI process). */ if (ret == HTTP_NOT_MODIFIED) { r->status = ret; return OK; } return ret; } const char *location = apr_table_get(r->headers_out, "Location"); #if 0 if (location && r->status == 200) { /* For a redirect whether internal or not, discard any * remaining stdout from the script, and log any remaining * stderr output, as normal. */ discard_script_output(bb); apr_brigade_destroy(bb); apr_file_pipe_timeout_set(script_err, r->server->timeout); log_script_err(r, script_err); } #endif if (location && location[0] == '/' && r->status == 200) { /* This redirect needs to be a GET no matter what the original * method was. */ r->method = apr_pstrdup(r->pool, "GET"); r->method_number = M_GET; /* We already read the message body (if any), so don't allow * the redirected request to think it has one. We can ignore * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. */ apr_table_unset(r->headers_in, "Content-Length"); ap_internal_redirect_handler(location, r); return OK; } else if (location && r->status == 200) { /* XX Note that if a script wants to produce its own Redirect * body, it now has to explicitly *say* "Status: 302" */ return HTTP_MOVED_TEMPORARILY; } }
static int cgi_handler(request_rec *r) { int nph; apr_size_t dbpos = 0; const char *argv0; const char *command; const char **argv; char *dbuf = NULL; apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL; apr_bucket_brigade *bb; apr_bucket *b; int is_included; int seen_eos, child_stopped_reading; apr_pool_t *p; cgi_server_conf *conf; apr_status_t rv; cgi_exec_info_t e_info; conn_rec *c = r->connection; if(strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) return DECLINED; is_included = !strcmp(r->protocol, "INCLUDED"); p = r->main ? r->main->pool : r->pool; argv0 = apr_filepath_name_get(r->filename); nph = !(strncmp(argv0, "nph-", 4)); conf = ap_get_module_config(r->server->module_config, &cgi_module); if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "Options ExecCGI is off in this directory"); if (nph && is_included) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "attempt to include NPH CGI script"); if (r->finfo.filetype == 0) return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, "script not found or unable to stat"); if (r->finfo.filetype == APR_DIR) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "attempt to invoke directory as script"); if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) && r->path_info && *r->path_info) { /* default to accept */ return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, "AcceptPathInfo off disallows user's path"); } /* if (!ap_suexec_enabled) { if (!ap_can_exec(&r->finfo)) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "file permissions deny server execution"); } */ ap_add_common_vars(r); ap_add_cgi_vars(r); e_info.process_cgi = 1; e_info.cmd_type = APR_PROGRAM; e_info.detached = 0; e_info.in_pipe = APR_CHILD_BLOCK; e_info.out_pipe = APR_CHILD_BLOCK; e_info.err_pipe = APR_CHILD_BLOCK; e_info.prog_type = RUN_AS_CGI; e_info.bb = NULL; e_info.ctx = NULL; e_info.next = NULL; e_info.addrspace = 0; /* build the command line */ if ((rv = cgi_build_command(&command, &argv, r, p, &e_info)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "don't know how to spawn child process: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* run the script in its own process */ if ((rv = run_cgi_child(&script_out, &script_in, &script_err, command, argv, r, p, &e_info)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "couldn't spawn child process: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* Transfer any put/post args, CERN style... * Note that we already ignore SIGPIPE in the core server. */ bb = apr_brigade_create(r->pool, c->bucket_alloc); seen_eos = 0; child_stopped_reading = 0; if (conf->logname) { dbuf = apr_palloc(r->pool, conf->bufbytes + 1); dbpos = 0; } do { apr_bucket *bucket; rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Error reading request entity data"); return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); } for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket = APR_BUCKET_NEXT(bucket)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(bucket)) { seen_eos = 1; break; } /* We can't do much with this. */ if (APR_BUCKET_IS_FLUSH(bucket)) { continue; } /* If the child stopped, we still must read to EOS. */ if (child_stopped_reading) { continue; } /* read */ apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); if (conf->logname && dbpos < conf->bufbytes) { int cursize; if ((dbpos + len) > conf->bufbytes) { cursize = conf->bufbytes - dbpos; } else { cursize = len; } memcpy(dbuf + dbpos, data, cursize); dbpos += cursize; } /* Keep writing data to the child until done or too much time * elapses with no progress or an error occurs. */ rv = apr_file_write_full(script_out, data, len, NULL); if (rv != APR_SUCCESS) { /* silly script stopped reading, soak up remaining message */ child_stopped_reading = 1; } } apr_brigade_cleanup(bb); } while (!seen_eos); if (conf->logname) { dbuf[dbpos] = '\0'; } /* Is this flush really needed? */ apr_file_flush(script_out); apr_file_close(script_out); AP_DEBUG_ASSERT(script_in != NULL); apr_brigade_cleanup(bb); #if APR_FILES_AS_SOCKETS apr_file_pipe_timeout_set(script_in, 0); apr_file_pipe_timeout_set(script_err, 0); b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc); #else b = apr_bucket_pipe_create(script_in, c->bucket_alloc); #endif APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); /* Handle script return... */ if (!nph) { const char *location; char sbuf[MAX_STRING_LEN]; int ret; if ((ret = ap_scan_script_header_err_brigade(r, bb, sbuf))) { ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err); /* * ret could be HTTP_NOT_MODIFIED in the case that the CGI script * does not set an explicit status and ap_meets_conditions, which * is called by ap_scan_script_header_err_brigade, detects that * the conditions of the requests are met and the response is * not modified. * In this case set r->status and return OK in order to prevent * running through the error processing stack as this would * break with mod_cache, if the conditions had been set by * mod_cache itself to validate a stale entity. * BTW: We circumvent the error processing stack anyway if the * CGI script set an explicit status code (whatever it is) and * the only possible values for ret here are: * * HTTP_NOT_MODIFIED (set by ap_meets_conditions) * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the * processing of the response of the CGI script, e.g broken headers * or a crashed CGI process). */ if (ret == HTTP_NOT_MODIFIED) { r->status = ret; return OK; } return ret; } location = apr_table_get(r->headers_out, "Location"); if (location && r->status == 200) { /* For a redirect whether internal or not, discard any * remaining stdout from the script, and log any remaining * stderr output, as normal. */ discard_script_output(bb); apr_brigade_destroy(bb); apr_file_pipe_timeout_set(script_err, r->server->timeout); log_script_err(r, script_err); } if (location && location[0] == '/' && r->status == 200) { /* This redirect needs to be a GET no matter what the original * method was. */ r->method = apr_pstrdup(r->pool, "GET"); r->method_number = M_GET; /* We already read the message body (if any), so don't allow * the redirected request to think it has one. We can ignore * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. */ apr_table_unset(r->headers_in, "Content-Length"); ap_internal_redirect_handler(location, r); return OK; } else if (location && r->status == 200) { /* XX Note that if a script wants to produce its own Redirect * body, it now has to explicitly *say* "Status: 302" */ return HTTP_MOVED_TEMPORARILY; } rv = ap_pass_brigade(r->output_filters, bb); } else /* nph */ { struct ap_filter_t *cur; /* get rid of all filters up through protocol... since we * haven't parsed off the headers, there is no way they can * work */ cur = r->proto_output_filters; while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { cur = cur->next; } r->output_filters = r->proto_output_filters = cur; rv = ap_pass_brigade(r->output_filters, bb); } /* don't soak up script output if errors occurred writing it * out... otherwise, we prolong the life of the script when the * connection drops or we stopped sending output for some other * reason */ if (rv == APR_SUCCESS && !r->connection->aborted) { apr_file_pipe_timeout_set(script_err, r->server->timeout); log_script_err(r, script_err); } apr_file_close(script_err); return OK; /* NOT r->status, even if it has changed. */ }
static int handle_request(request_rec * r, int role, char *hdr_msg, char *env_msg) { pool *request_pool = r->main ? r->main->pool : r->pool; server_rec *main_server = r->server; jaxer_bucket_ctx *ctx; apr_status_t rv; const char *location; unsigned char *buf; int got_header = 0; int postdata_sent = 0; jaxer_worker *worker; // Need to get this from config jaxer_connection *ac; int should_redirect = 0; worker = get_worker_by_name(main_server, "worker1"); ctx = ap_pcalloc(request_pool, sizeof(*ctx)); if (!ctx) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), r, "mod_jaxer: apr_calloc bucket_ctx failed in handle_request function"); return HTTP_INTERNAL_SERVER_ERROR; } if ((rv = jxr_conn_open(worker, &ctx->ac, r))!= APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_jaxer: can't connect to socket"); ctx->ac->has_error = 1; return HTTP_SERVICE_UNAVAILABLE; } ac = ctx->ac; ap_register_cleanup(request_pool, ctx->ac, jaxer_connection_cleanup, apr_pool_cleanup_null); // SEND HEADER if ((rv = jxr_send_message(ctx->ac, hdr_msg)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: send HTTP header to jaxer server failed"); ac->has_error = 1; return HTTP_INTERNAL_SERVER_ERROR; } // SEND ENV HEADER if ((rv = jxr_send_message(ctx->ac, env_msg)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: send environment vars to jaxer server failed"); ac->has_error = 1; return HTTP_INTERNAL_SERVER_ERROR; } /* TODO: May need to send an empty doc */ if ((rv = jxr_send_message_add_header(ac, 0, 0, BLOCKTYPE_DOCUMENT)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: send emptty doc to jaxer error"); ac->has_error = 1; return HTTP_INTERNAL_SERVER_ERROR; } if ((rv = jxr_send_message_add_header(ac, 0, 0, BLOCKTYPE_ENDREQUEST)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: write end of (doc) request to jaxer server failed"); ac->has_error = 1; return HTTP_INTERNAL_SERVER_ERROR; } /* * Now get a response, to see if Jaxer wants anything until we get a header back */ got_header = 0; while (!got_header) { char msg_type; if ((rv = jxr_receive_message(ac, &buf)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: check for request message failed"); ac->has_error = 1; return rv; } msg_type = jxr_msg_get_type(buf); switch ( msg_type) { // char uri[MAX_STRING_LEN]; // apr_size_t pos, len; case BLOCKTYPE_REQUEST_POSTDATA: if (postdata_sent) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_jaxer: requesting postdata again"); ac->has_error = 1; return rv; } if ((rv = jxr_send_postdata(ac, r)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_jaxer: error while sending postdata"); ac->has_error = 1; return rv; } postdata_sent = 1; break; case BLOCKTYPE_HTTP_HEADER: got_header = 1; break; default: compat_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_jaxer: invalid request (type=%d) received", msg_type); ac->has_error = 1; return (!APR_SUCCESS); break; } } if ((rv = jxr_process_response_headers(r, buf)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: process response header failed"); ac->has_error = 1; return rv; } /* Check redirect */ location = ap_table_get(r->headers_out, "Location"); if (location && location[0]) { should_redirect = 1; compat_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "mod_jaxer: request (status=%d) will be redirected to %s", r->status, location); } if (should_redirect) { /* This redirect needs to be a GET no matter what the original * method was. */ r->method = ap_pstrdup(r->pool, "GET"); r->method_number = M_GET; /* We already read the message body (if any), so don't allow * the redirected request to think it has one. We can ignore * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. */ ap_table_unset(r->headers_in, "Content-Length"); compat_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "mod_jaxer: redirecting request to %s", location); ap_internal_redirect_handler(location, r); return APR_SUCCESS; } /* Now pass to output filter */ if (role == FCGI_RESPONDER && (rv = jxr_process_response_body(ac, r)) != APR_SUCCESS) { compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: process_response_body failed"); return HTTP_INTERNAL_SERVER_ERROR; } return HTTP_OK; }