/*
 * 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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
/* 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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
static int suphp_handler(request_rec *r) {
    suphp_conf *sconf;
    suphp_conf *dconf;

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

    struct stat finfo;

    int rv;

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

    pool *p;

    BUFF *script_in, *script_out, *script_err;

    const char *handler;

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

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

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

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

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

    /* check if file is existing and accessible */

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

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

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

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

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

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

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

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


    /* prepare environment for new process */

    ap_add_common_vars(r);
    ap_add_cgi_vars(r);

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

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

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

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

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

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

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

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

    /* Fork child process */

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

    /* Transfer request body to script */

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

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

        ap_hard_timeout("reading request body", r);

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

        ap_bflush(script_in);
        ap_kill_timeout(r);
    }

    ap_bclose(script_in);

    /* Transfer output from script to client */

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

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

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

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

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

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

        /* Output headers and body */

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

    return OK;
}
Ejemplo n.º 8
0
/* 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. */
}
Ejemplo n.º 10
0
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;
}