예제 #1
0
/**
 * Writes headers to srun.
 */
static void
write_headers(stream_t *s, request_rec *r)
{
  array_header *hdrs_arr = ap_table_elts(r->headers_in);
  table_entry *hdrs = (table_entry *) hdrs_arr->elts;
  int i;

  for (i = 0; i < hdrs_arr->nelts; ++i) {
    char *key = hdrs[i].key;
    char *value = hdrs[i].val;
    
    if (! key)
      continue;

    /*
     * Content-type and Content-Length are special cased for a little
     * added efficiency.
     */
    if (! strcasecmp(key, "Content-type"))
      cse_write_string(s, CSE_CONTENT_TYPE, value);
    else if (! strcasecmp(key, "Content-length"))
      cse_write_string(s, CSE_CONTENT_LENGTH, value);
    else {
      cse_write_string(s, HMUX_HEADER, key);
      cse_write_string(s, HMUX_STRING, value);
    }
  }
}
예제 #2
0
static PyObject * req_get_all_dirs(requestobject *self, PyObject *args)
{
    table *all;
    py_dir_config *conf =
	(py_dir_config *) ap_get_module_config(self->request_rec->per_dir_config, 
					       &python_module);

    all = ap_copy_table(self->request_rec->pool, conf->dirs);

    if (ap_table_get(self->request_rec->notes, "py_more_directives")) {

	array_header *ah = ap_table_elts(self->request_rec->notes);
	table_entry *elts = (table_entry *)ah->elts;
	int i = ah->nelts;

	while (i--) {
	    if (elts[i].key) {
		
		/* chop off _dir */
		char *s = ap_pstrdup(self->request_rec->pool, elts[i].key);
		if (valid_handler(s)) {
		    
		    s[strlen(s)-4] = 0;
		    ap_table_set(all, s, elts[i].val);
		}
	    }
	}
    }
    return MpTable_FromTable(all);
}
static char *wrap_iterenv (void *data, int x, char **k, char **v)
{
  WRAPPER_DATA *wrap = (WRAPPER_DATA *)data;
  array_header *env = ap_table_elts(wrap->r->subprocess_env);
  table_entry *entry = (table_entry*)env->elts;

  if (x >= env->nelts) return 0;

  if (entry[x].key == NULL || entry[x].val == NULL)
    return 0;

  *k = strdup(entry[x].key);
  *v = strdup(entry[x].val);

  return 0;
}	
예제 #4
0
static void
write_added_headers(stream_t *s, request_rec *r)
{
  array_header *hdrs_arr = ap_table_elts(r->subprocess_env);
  table_entry *hdrs = (table_entry *) hdrs_arr->elts;
  int i;
  int has_ssl = 0;

  for (i = 0; i < hdrs_arr->nelts; ++i) {
    char *key = hdrs[i].key;
    char *value = hdrs[i].val;
    
    if (! key)
      continue;

    /* skip leading whitespace */
    for (; isspace(*value); value++) {
    }

    if (! strcmp(key, "HTTPS") &&
	! strcasecmp(value, "on")) {
      has_ssl = 1;
      cse_write_string(s, CSE_IS_SECURE, "");
    }
    else if (*key == 'S' && ! r->connection->user &&
             ! strcmp(key, "SSL_CLIENT_DN"))
      cse_write_string(s, CSE_REMOTE_USER, value);

    cse_write_string(s, HMUX_HEADER, key);
    cse_write_string(s, HMUX_STRING, value);
  }

  if (has_ssl)
    write_ssl_env(s, r);

  if (r->prev) {
    if (r->prev->args) {
      cse_write_string(s, HMUX_HEADER, "REDIRECT_QUERY_STRING");
      cse_write_string(s, HMUX_STRING, r->prev->args);
    }
    
    if (r->prev->uri) {
      cse_write_string(s, HMUX_HEADER, "REDIRECT_URL");
      cse_write_string(s, HMUX_STRING, r->prev->uri);
    }
  }
}
예제 #5
0
/**
 * Gets the session index from the request
 *
 * Cookies have priority over the query
 *
 * @return -1 if no session
 */
static int
get_session_index(config_t *config, request_rec *r, int *backup)
{
  array_header *hdrs_arr = ap_table_elts(r->headers_in);
  table_entry *hdrs = (table_entry *) hdrs_arr->elts;
  int i;
  int session;
  char *uri;

  for (i = 0; i < hdrs_arr->nelts; ++i) {
    if (! hdrs[i].key || ! hdrs[i].val)
      continue;

    if (strcasecmp(hdrs[i].key, "Cookie"))
      continue;

    session = cse_session_from_string(hdrs[i].val,
                                      config->session_cookie,
                                      backup);
    if (session >= 0)
      return session;
  }

  if (r->request_config)
    uri = ap_get_module_config(r->request_config, &caucho_module);

  if (uri) {
    if (*config->alt_session_url_prefix)
      return cse_session_from_string(uri,
				     config->alt_session_url_prefix,
				     backup);
    else
      return cse_session_from_string(uri + strlen(config->session_url_prefix),
				     "", backup);
  }

  if (*config->alt_session_url_prefix) {
    return cse_session_from_string(r->uri,
				   config->alt_session_url_prefix,
				   backup);
  }
  else
    return cse_session_from_string(r->uri, config->session_url_prefix, backup);
}
예제 #6
0
API_EXPORT(char **) ap_create_environment(pool *p, table *t)
{
    array_header *env_arr = ap_table_elts(t);
    table_entry *elts = (table_entry *) env_arr->elts;
    char **env = (char **) ap_palloc(p, (env_arr->nelts + 2) * sizeof(char *));
    int i, j;
    char *tz;
    char *whack;

    j = 0;
    if (!ap_table_get(t, "TZ")) {
	tz = getenv("TZ");
	if (tz != NULL) {
	    env[j++] = ap_pstrcat(p, "TZ=", tz, NULL);
	}
    }
    for (i = 0; i < env_arr->nelts; ++i) {
        if (!elts[i].key) {
	    continue;
	}
	env[j] = ap_pstrcat(p, elts[i].key, "=", elts[i].val, NULL);
	whack = env[j];
	if (ap_isdigit(*whack)) {
	    *whack++ = '_';
	}
	while (*whack != '=') {
	    if (!ap_isalnum(*whack) && *whack != '_') {
		*whack = '_';
	    }
	    ++whack;
	}
	++j;
    }

    env[j] = NULL;
    return env;
}
예제 #7
0
static PyObject * req_get_all_config(requestobject *self, PyObject *args)
{
    table *all;
    py_dir_config *conf =
	(py_dir_config *) ap_get_module_config(self->request_rec->per_dir_config, 
					       &python_module);

    all = ap_copy_table(self->request_rec->pool, conf->directives);

    if (ap_table_get(self->request_rec->notes, "py_more_directives")) {

	array_header *ah = ap_table_elts(self->request_rec->notes);
	table_entry *elts = (table_entry *)ah->elts;
	int i = ah->nelts;

	while (i--) {
	    if (elts[i].key) {
		if (valid_handler(elts[i].key)) {
		
		    /* if exists - append, otherwise add */
		    const char *val = ap_table_get(all, elts[i].key);
		    if (val) {
			ap_table_set(all, elts[i].key, 
				     ap_pstrcat(self->request_rec->pool,
						val, " ", elts[i].val,
						NULL));
		    }
		    else {
			ap_table_set(all, elts[i].key, elts[i].val);
		    }
		}
	    }
	}
    }
    return MpTable_FromTable(all);
}
예제 #8
0
BOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName,
                               LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer) {
    request_rec *r = ((isapi_cid *)hConn)->r;
    const char *result;
    DWORD len;

    if (!strcmp(lpszVariableName, "ALL_HTTP")) {
        /* lf delimited, colon split, comma seperated and 
         * null terminated list of HTTP_ vars 
         */
        char **env = (char**) ap_table_elts(r->subprocess_env)->elts;
        int nelts = 2 * ap_table_elts(r->subprocess_env)->nelts;
        int i;

        for (len = 0, i = 0; i < nelts; i += 2)
            if (!strncmp(env[i], "HTTP_", 5))
                len += strlen(env[i]) + strlen(env[i + 1]) + 2;
  
        if (*lpdwSizeofBuffer < len + 1) {
            *lpdwSizeofBuffer = len + 1;
            SetLastError(ERROR_INSUFFICIENT_BUFFER);
            return FALSE;
        }
    
        for (i = 0; i < nelts; i += 2)
            if (!strncmp(env[i], "HTTP_", 5)) {
                strcpy(lpvBuffer, env[i]);
                ((char*)lpvBuffer) += strlen(env[i]);
                *(((char*)lpvBuffer)++) = ':';
                strcpy(lpvBuffer, env[i + 1]);
                ((char*)lpvBuffer) += strlen(env[i + 1]);
                *(((char*)lpvBuffer)++) = '\n';
            }            
        *(((char*)lpvBuffer)++) = '\0';
        *lpdwSizeofBuffer = len;
        return TRUE;
    }

    if (!strcmp(lpszVariableName, "ALL_RAW")) {
        /* lf delimited, colon split, comma seperated and 
         * null terminated list of the raw request header
         */
        char **raw = (char**) ap_table_elts(r->headers_in)->elts;
        int nelts = 2 * ap_table_elts(r->headers_in)->nelts;
        int i;        
        
        for (len = 0, i = 0; i < nelts; i += 2)
            len += strlen(raw[i]) + strlen(raw[i + 1]) + 2;
  
        if (*lpdwSizeofBuffer < len + 1) {
            *lpdwSizeofBuffer = len + 1;
            SetLastError(ERROR_INSUFFICIENT_BUFFER);
            return FALSE;
        }
    
        for (i = 0; i < nelts; i += 2) {
            strcpy(lpvBuffer, raw[i]);
            ((char*)lpvBuffer) += strlen(raw[i]);
            *(((char*)lpvBuffer)++) = ':';
            *(((char*)lpvBuffer)++) = ' ';
            strcpy(lpvBuffer, raw[i + 1]);
            ((char*)lpvBuffer) += strlen(raw[i + 1]);
            *(((char*)lpvBuffer)++) = '\n';
            i += 2;
        }
        *(((char*)lpvBuffer)++) = '\0';
        *lpdwSizeofBuffer = len;
        return TRUE;
    }

    /* Not a special case */
    result = ap_table_get(r->subprocess_env, lpszVariableName);
    if (result) {
        len = strlen(result);
        if (*lpdwSizeofBuffer < len + 1) {
            *lpdwSizeofBuffer = len + 1;
            SetLastError(ERROR_INSUFFICIENT_BUFFER);
            return FALSE;
        }
        strcpy(lpvBuffer, result);
        *lpdwSizeofBuffer = len;
        return TRUE;
    }

    /* Not Found */
    SetLastError(ERROR_INVALID_INDEX);
    return FALSE;
}
예제 #9
0
/* ====================================================================
 * Here's the real content handler.
 * ==================================================================== */
static int content_handler(request_rec *r)
{
    long length;
    wkcfg *cfg;
    WFILE* env_dict = NULL;
    int i;
    char msgbuf[MAX_STRING_LEN];
    int conn_attempt = 0;
    WFILE* whole_dict = NULL;
    WFILE* int_dict = NULL;
    const char *value;
    const char *key;
    array_header *hdr_arr;
    table_entry *elts;

    cfg = ap_get_module_config(r->per_dir_config, &webkit_module);
    if (cfg == NULL) {
        log_debug("No cfg", r);
        cfg = (wkcfg*)wk_create_dir_config(r->pool, "/");
    }

    env_dict = setup_WFILE(r);
    whole_dict = setup_WFILE(r);
    int_dict = setup_WFILE(r);

    if (env_dict == NULL || whole_dict == NULL) {
        log_error("Couldn't allocate Python data structures", r->server);
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    ap_add_common_vars(r);
    ap_add_cgi_vars(r); /* not included in the common_vars above */

    /* Build the environment dictionary */

    hdr_arr = ap_table_elts(r->subprocess_env);
    elts = (table_entry *)hdr_arr->elts;

    /* start dictionary */
    w_byte(TYPE_DICT, env_dict);

    for (i = 0; i < hdr_arr->nelts; ++i) {
        if (!elts[i].key)
            continue;
        key = elts[i].key;
        value = ap_table_get(r->subprocess_env, elts[i].key);
        write_string(key, env_dict);
        if (value != NULL)
            write_string(value, env_dict);
        else
            w_byte(TYPE_NONE, env_dict);
    }
    hdr_arr = cfg->passheaders;
    if (hdr_arr) {
        char **headers = (char **)hdr_arr->elts;
        for (i = 0; i < hdr_arr->nelts; i++) {
            key = headers[i];
            value = ap_table_get(r->headers_in, key);
            if (value && *value) {
                write_string(key, env_dict);
                write_string(value, env_dict);
            }
        }
    }

#ifdef SECURITY_HOLE_PASS_AUTHORIZATION
    /* Ordinarily Apache only makes the username available to CGI scripts,
    keeping the password secret. It can be configured to make the complete
    credential details available, but only by completely rebuilding the
    server with SECURITY_HOLE_PASS_AUTHORIZATION set (enabling this feature
    is considered a security risk). By setting the same constant, you can
    have mod_webkit pass the authorization information to WebKit instead.
    (suggested by Maximillian Dornseif 2003-10-27) */
    key = "Authorization";
    value = ap_table_get(r->headers_in, key);
    if (value && *value) {
      write_string("X-HTTP_AUTHORIZATION", env_dict);
      write_string(value, env_dict);
    }
#endif

    w_byte(TYPE_NULL, env_dict);
    /* end dictionary */
    log_debug("Built env dictionary", r);

    /* We can start building the full dictionary now */
    w_byte(TYPE_DICT, whole_dict);
    write_string("format", whole_dict); /* key */
    write_string("CGI", whole_dict); /* value */
    write_string("time", whole_dict); /* key */
    w_byte(TYPE_INT, whole_dict); /* value */
    /* patch from Ken Lalonde to make the time entry useful */
    w_long((long)r->request_time, whole_dict); /* value */

    write_string("environ", whole_dict); /* key */

    /* copy env_dict into whole_dict */
    insert_data(whole_dict, env_dict);

    /* that should be it */
    /* end dictionary */
    w_byte(TYPE_NULL, whole_dict);

    length = whole_dict->ptr - whole_dict->str;

    write_integer((int)length, int_dict);

    /* now we try to send it */
    for (conn_attempt = 1; conn_attempt <= cfg->retryattempts; conn_attempt++) {
        int result = transact_with_app_server(r, cfg, whole_dict, int_dict, length);
        if (result == 0) {
            return OK;
        } else if (result == 2) {
            log_error("error transacting with app server -- giving up.", r->server);
            return HTTP_INTERNAL_SERVER_ERROR;
        }
        sprintf(msgbuf,
            "Couldn't connect to AppServer, attempt %i of %i",
            conn_attempt, cfg->retryattempts);
        log_error(msgbuf, r->server);
        sleep(cfg->retrydelay);
    }
    log_error("error transacting with app server -- giving up.", r->server);
    return HTTP_INTERNAL_SERVER_ERROR;
}
예제 #10
0
API_EXPORT(void) ap_add_common_vars(request_rec *r)
{
    table *e;
    server_rec *s = r->server;
    conn_rec *c = r->connection;
    const char *rem_logname;
    char *env_path;
#if defined(WIN32) || defined(OS2)
    char *env_temp;
#endif
    const char *host;
    array_header *hdrs_arr = ap_table_elts(r->headers_in);
    table_entry *hdrs = (table_entry *) hdrs_arr->elts;
    int i;
    char servbuf[NI_MAXSERV];

    /* use a temporary table which we'll overlap onto
     * r->subprocess_env later
     */
    e = ap_make_table(r->pool, 25 + hdrs_arr->nelts);

    /* First, add environment vars from headers... this is as per
     * CGI specs, though other sorts of scripting interfaces see
     * the same vars...
     */

    for (i = 0; i < hdrs_arr->nelts; ++i) {
        if (!hdrs[i].key) {
	    continue;
	}

	/* A few headers are special cased --- Authorization to prevent
	 * rogue scripts from capturing passwords; content-type and -length
	 * for no particular reason.
	 */

	if (!strcasecmp(hdrs[i].key, "Content-type")) {
	    ap_table_addn(e, "CONTENT_TYPE", hdrs[i].val);
	}
	else if (!strcasecmp(hdrs[i].key, "Content-length")) {
	    ap_table_addn(e, "CONTENT_LENGTH", hdrs[i].val);
	}
	/*
	 * You really don't want to disable this check, since it leaves you
	 * wide open to CGIs stealing passwords and people viewing them
	 * in the environment with "ps -e".  But, if you must...
	 */
#ifndef SECURITY_HOLE_PASS_AUTHORIZATION
	else if (!strcasecmp(hdrs[i].key, "Authorization") 
		 || !strcasecmp(hdrs[i].key, "Proxy-Authorization")) {
	    continue;
	}
#endif
	else {
	    ap_table_addn(e, http2env(r->pool, hdrs[i].key), hdrs[i].val);
	}
    }

    if (!(env_path = ap_pstrdup(r->pool, getenv("PATH")))) {
	env_path = DEFAULT_PATH;
    }

#ifdef WIN32
    if (env_temp = getenv("SystemRoot")) {
        ap_table_addn(e, "SystemRoot", env_temp);         
    }
    if (env_temp = getenv("COMSPEC")) {
        ap_table_addn(e, "COMSPEC", env_temp);            
    }
    if (env_temp = getenv("WINDIR")) {
        ap_table_addn(e, "WINDIR", env_temp);
    }
#endif

#ifdef OS2
    if ((env_temp = getenv("COMSPEC")) != NULL) {
        ap_table_addn(e, "COMSPEC", env_temp);            
    }
    if ((env_temp = getenv("ETC")) != NULL) {
        ap_table_addn(e, "ETC", env_temp);            
    }
    if ((env_temp = getenv("DPATH")) != NULL) {
        ap_table_addn(e, "DPATH", env_temp);            
    }
    if ((env_temp = getenv("PERLLIB_PREFIX")) != NULL) {
        ap_table_addn(e, "PERLLIB_PREFIX", env_temp);            
    }
#endif

    ap_table_addn(e, "PATH", env_path);
    ap_table_addn(e, "SERVER_SIGNATURE", ap_psignature("", r));
    ap_table_addn(e, "SERVER_SOFTWARE", ap_get_server_version());
    ap_table_addn(e, "SERVER_NAME", 
		  ap_escape_html(r->pool,ap_get_server_name(r)));
    ap_table_addn(e, "SERVER_ADDR", r->connection->local_ip);	/* Apache */
    ap_table_addn(e, "SERVER_PORT",
		  ap_psprintf(r->pool, "%u", ap_get_server_port(r)));
    host = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST);
    if (host) {
	ap_table_addn(e, "REMOTE_HOST", host);
    }
    ap_table_addn(e, "REMOTE_ADDR", c->remote_ip);
    ap_table_addn(e, "DOCUMENT_ROOT", ap_document_root(r));	/* Apache */
    ap_table_addn(e, "SERVER_ADMIN", s->server_admin);	/* Apache */
    ap_table_addn(e, "SCRIPT_FILENAME", r->filename);	/* Apache */

    servbuf[0] = '\0';
    if (!getnameinfo((struct sockaddr *)&c->remote_addr,
#ifndef HAVE_SOCKADDR_LEN
		     SA_LEN((struct sockaddr *)&c->remote_addr),
#else
		     c->remote_addr.ss_len,
#endif
		     NULL, 0, servbuf, sizeof(servbuf), NI_NUMERICSERV)){
	ap_table_addn(e, "REMOTE_PORT", ap_pstrdup(r->pool, servbuf));
    }

    if (c->user) {
	ap_table_addn(e, "REMOTE_USER", c->user);
    }
    if (c->ap_auth_type) {
	ap_table_addn(e, "AUTH_TYPE", c->ap_auth_type);
    }
    rem_logname = ap_get_remote_logname(r);
    if (rem_logname) {
	ap_table_addn(e, "REMOTE_IDENT", ap_pstrdup(r->pool, rem_logname));
    }

    /* Apache custom error responses. If we have redirected set two new vars */

    if (r->prev) {
        if (r->prev->args) {
	    ap_table_addn(e, "REDIRECT_QUERY_STRING", r->prev->args);
	}
	if (r->prev->uri) {
	    ap_table_addn(e, "REDIRECT_URL", r->prev->uri);
	}
    }

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

    ap_kill_timeout(r);

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

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

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

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

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

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

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

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

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

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

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

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

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

    ap_proxy_cache_tidy(c);

    ap_proxy_garbage_coll(r);
    return OK;
}
예제 #12
0
static apr_size_t jxr_build_header(char* buf, int which, table *t)
{
	// If buf is NULL, we just computer the length required.  Otherwise, we fill
	// buf with the actual data.
	// which is ENV_PRMS or HDR_PRMS

	const array_header *env_arr = ap_table_elts(t);
    const table_entry *elts = (const table_entry *) env_arr->elts;
	int i;
    char *tz;
    
	apr_size_t pos;
	apr_size_t num_pos; // Remember where the number of headers will be.
	char type; //This is the type of this message.  EG HEADER, POST, BODY etc
	int num_hds = 0;

	// resetMessage(&pos);
	if (buf)
	{
		type = (which==ENV_PRMS) ? BLOCKTYPE_ENVIRO_VARS : BLOCKTYPE_HTTP_HEADER;
		jxr_msg_init(buf, &pos, type);
		num_pos = pos;

		// Place holder for actual number of headers
		jxr_msg_append_int16(buf, &pos, 0);
	}else
	{
		pos = 2 + sizeof(Jaxer_Header);
	}


    if (which == ENV_PRMS && !ap_table_get(t, "TZ"))
	{
        tz = getenv("TZ");
        if (tz != NULL)
		{
			if (buf)
			{
				jxr_msg_append_string(buf, &pos, "TZ");
				jxr_msg_append_string(buf, &pos, tz);
				num_hds++;
			}else
			{
				pos += 4; // Lengths
				pos += 2; // Length of "TZ"
				pos += (int) strlen(tz);
			}
        }
    }
    for (i = 0; i < env_arr->nelts; ++i)
	{
        if (!elts[i].key)
		{
            continue;
        }
		if (buf)
		{
			jxr_msg_append_string(buf, &pos, elts[i].key);
			jxr_msg_append_string(buf, &pos, elts[i].val);
			num_hds++;
		}else
		{
			pos += 4;
			pos += (int) strlen(elts[i].key);
			pos += (int) strlen(elts[i].val);
		}
	}
       
	if (buf)
	{
		// overriding
		jxr_msg_append_int16(buf, &num_pos, num_hds);

		// Fill the Header of message
		jxr_msg_end(buf, &pos);
	}

    return pos;
}