static dav_error *
dav_rawx_set_headers(request_rec *r, const dav_resource *resource)
{
	if (!resource->exists)
		return NULL;

	DAV_DEBUG_REQ(r, 0, "%s(%s)", __FUNCTION__, resource_get_pathname(resource));

	/* make sure the proper mtime is in the request record */
	ap_update_mtime(r, resource->info->finfo.mtime);
	ap_set_last_modified(r);
	ap_set_etag(r);

	/* we accept byte-ranges */
	apr_table_setn(r->headers_out, apr_pstrdup(r->pool, "Accept-Ranges"),
			apr_pstrdup(r->pool, "bytes"));

	/* set up the Content-Length header */
	ap_set_content_length(r, resource->info->finfo.size);

	request_fill_headers(r, &(resource->info->chunk));

	/* compute metadata_compress if compressed content */
	if (resource->info->compression) {
		char *buf = apr_pstrcat(r->pool, "compression=on;compression_algorithm=", resource->info->compress_algo,
				";compression_blocksize=", apr_psprintf(r->pool, "%d", resource->info->cp_chunk.block_size), ";", NULL);
		apr_table_setn(r->headers_out, apr_pstrdup(r->pool, "metadatacompress"), buf);
	}

	return NULL;
}
Example #2
0
static int write_http_response(mapcache_context_apache_request *ctx, mapcache_http_response *response) {
   request_rec *r = ctx->request;
   int rc;

   if(response->mtime) {
      ap_update_mtime(r, response->mtime);
      if((rc = ap_meets_conditions(r)) != OK) {
         return rc;
      }
      char *timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
      apr_rfc822_date(timestr, response->mtime);
      apr_table_setn(r->headers_out, "Last-Modified", timestr);
   }
   if(response->headers && !apr_is_empty_table(response->headers)) {
      const apr_array_header_t *elts = apr_table_elts(response->headers);
      int i;
      for(i=0;i<elts->nelts;i++) {
         apr_table_entry_t entry = APR_ARRAY_IDX(elts,i,apr_table_entry_t);
         if(!strcasecmp(entry.key,"Content-Type")) {
            ap_set_content_type(r,entry.val);
         } else {
            apr_table_set(r->headers_out, entry.key, entry.val);
         }
      }
   }
   if(response->data) {
      ap_set_content_length(r,response->data->size);
      ap_rwrite((void*)response->data->buf, response->data->size, r);
   }

   r->status = response->code;
   return OK;

}
Example #3
0
static int req_update_mtime(lua_State* L)
{
  request_rec *r = CHECK_REQUEST_OBJECT(1);
  int mtime = luaL_checkint(L, 2);

  ap_update_mtime(r, apr_time_from_sec(mtime));

  return 0;
}
Example #4
0
static int req_set_last_modified(lua_State* L)
{
  request_rec *r = CHECK_REQUEST_OBJECT(1);
  lua_Integer mtime = luaL_optinteger(L, 2, 0);
  if (mtime)
  {
    ap_update_mtime(r, apr_time_from_sec(mtime));
  }
  ap_set_last_modified(r);

  return 0;
}
Example #5
0
static void accept_headers(cache_handle_t *h, request_rec *r)
{
    apr_table_t *cookie_table;
    const char *v;

    v = apr_table_get(h->resp_hdrs, "Content-Type");
    if (v) {
        ap_set_content_type(r, v);
        apr_table_unset(h->resp_hdrs, "Content-Type");
    }

    /* If the cache gave us a Last-Modified header, we can't just
     * pass it on blindly because of restrictions on future values.
     */
    v = apr_table_get(h->resp_hdrs, "Last-Modified");
    if (v) {
        ap_update_mtime(r, apr_date_parse_http(v));
        ap_set_last_modified(r);
        apr_table_unset(h->resp_hdrs, "Last-Modified");
    }

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

    apr_table_overlap(r->headers_out, h->resp_hdrs,
                      APR_OVERLAP_TABLES_SET);
    apr_table_overlap(r->err_headers_out, h->resp_err_hdrs,
                      APR_OVERLAP_TABLES_SET);
    if (!apr_is_empty_table(cookie_table)) {
        r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out,
                                               cookie_table);
    }
}
/**
 * Take two sets of headers, sandwich them together, and apply the result to
 * r->headers_out.
 *
 * To complicate this, a header may be duplicated in either table. Should a
 * header exist in the top table, all matching headers will be removed from
 * the bottom table before the headers are combined. The Warning headers are
 * handled specially. Warnings are added rather than being replaced, while
 * in the case of revalidation 1xx Warnings are stripped.
 *
 * The Content-Type and Last-Modified headers are then re-parsed and inserted
 * into the request.
 */
void cache_accept_headers(cache_handle_t *h, request_rec *r, apr_table_t *top,
        apr_table_t *bottom, int revalidation)
{
    const char *v;

    if (revalidation) {
        r->headers_out = apr_table_make(r->pool, 10);
        apr_table_do(filter_header_do, r->headers_out, bottom, NULL);
    }
    else if (r->headers_out != bottom) {
        r->headers_out = apr_table_copy(r->pool, bottom);
    }
    apr_table_do(remove_header_do, r->headers_out, top, NULL);
    apr_table_do(add_header_do, r->headers_out, top, NULL);

    v = apr_table_get(r->headers_out, "Content-Type");
    if (v) {
        ap_set_content_type(r, v);
        /*
         * Also unset possible Content-Type headers in r->headers_out and
         * r->err_headers_out as they may be different to what we have received
         * from the cache.
         * Actually they are not needed as r->content_type set by
         * ap_set_content_type above will be used in the store_headers functions
         * of the storage providers as a fallback and the HTTP_HEADER filter
         * does overwrite the Content-Type header with r->content_type anyway.
         */
        apr_table_unset(r->headers_out, "Content-Type");
        apr_table_unset(r->err_headers_out, "Content-Type");
    }

    /* If the cache gave us a Last-Modified header, we can't just
     * pass it on blindly because of restrictions on future values.
     */
    v = apr_table_get(r->headers_out, "Last-Modified");
    if (v) {
        ap_update_mtime(r, apr_date_parse_http(v));
        ap_set_last_modified(r);
    }

}
Example #7
0
/* Apache Handle Process and Output */
static int req_meets(lua_State*L )
{
  request_rec *r = CHECK_REQUEST_OBJECT(1);
  apr_time_t mtime = luaL_checkint(L, 2);
  int len = luaL_checkint(L, 3);
  int status;
  if (mtime)
    ap_update_mtime(r, mtime * APR_USEC_PER_SEC);
  ap_set_last_modified(r);
  ap_set_etag(r);
  ap_set_accept_ranges(r);
  apr_table_setn(r->headers_out, "Content-Length", apr_itoa(r->pool, len));
  status = ap_meets_conditions(r);
  if (status == 0)
  {
    lua_pushnil(L);
  }
  else
    lua_pushinteger(L, status);

  return 1;
}
Example #8
0
static int
aclr_handler(request_rec *r)
{
    int	rc;
    const char *idhead;
    char *real_uri;
    const char *docroot;
    size_t docroot_len;
    ap_filter_t *f, *nextf;
    char iredirect[MAX_STRING_LEN];

    aclr_dir_config *cfg = (aclr_dir_config *)ap_get_module_config
                           (r->per_dir_config, &aclr_module);

    if (cfg->state != ACLR_ENABLED) {
        return DECLINED;
    }

    if (!ap_is_initial_req(r)) {
        return DECLINED;
    }

    idhead = apr_table_get(r->headers_in, xa_int_name);

    if (idhead == NULL) {
        return DECLINED;
    }

#ifdef DEBUG
    const char *server_name = ap_get_server_name(r);
#endif

    docroot = ap_document_root(r);
    docroot_len = strlen(docroot);

    /* obtain real URI from filename - for rewrited URIs */
    if (strncmp(r->filename, docroot, docroot_len) != 0) {
        if (cfg->redirect_outside_of_docroot != ACLR_ENABLED) {

            aclr_debug(2, r->server, "file \"%s\" is outside of "
                       "DocumentRoot \"%s\": %s%s",
                       r->filename, docroot, server_name, r->uri);

            return DECLINED;
        }
        real_uri = r->uri;
    }
    else {
        real_uri = r->filename;
        real_uri += docroot_len;
    }

    snprintf(iredirect, sizeof(iredirect), "%s%s", idhead, real_uri);

    aclr_debug(3, r->server, "trying to process request: %s%s -> %s",
               server_name, r->uri, iredirect);

    aclr_debug(3, r->server, "r->filename: %s", r->filename);
    aclr_debug(3, r->server, "r->uri: %s", r->uri);
    aclr_debug(3, r->server, "docroot: %s", docroot);
    aclr_debug(3, r->server, "real_uri: %s", real_uri);

    if ((rc = ap_discard_request_body(r)) != OK) {
        return rc;
    }

    apr_table_set(r->headers_out, xa_ver_name, ACLR_VERSION);

    if ((r->method_number != M_GET) || (r->header_only)) {
        aclr_debug(2, r->server, "request method is not GET: %s%s",
                   server_name, r->uri);

        return DECLINED;
    }

    if (r->finfo.filetype != APR_REG) {
        aclr_debug(2, r->server, "request file not found "
                   "or is not regular file: %s%s",
                   server_name, r->uri);

        return DECLINED;
    }

    if (cfg->fsize != UNSET && r->finfo.size < cfg->fsize) {
        aclr_debug(2, r->server, "file size %lu < minsize %lu: %s%s",
                   r->finfo.size, cfg->fsize, server_name, r->uri);

        return DECLINED;
    }

    f = r->output_filters;
    do {
        nextf = f->next;
        aclr_debug(3, r->server, "output filter: %s", f->frec->name);
        if (strcmp(f->frec->name, "includes") == 0) {
            aclr_debug(2, r->server, "request uses INCLUDES filter: %s%s",
                       server_name, r->uri);

            return DECLINED;
        }
        f = nextf;
    } while (f && f != r->proto_output_filters);

    apr_table_set(r->headers_out, xa_redir_name, iredirect);

    r->header_only = 0;

    ap_update_mtime(r, r->finfo.mtime);

    aclr_debug(1, r->server, "request %s%s redirected to %s",
               server_name, r->uri, iredirect);

    return OK;
}
Example #9
0
/**
 * Sets the HTTP headers, like the size of the content, the modification date...
 * @param r        The request
 * @param resource The resource generated previously
 * @return         NULL on success
 */
static dav_error *dav_ns_set_headers(request_rec *r, const dav_resource *resource)
{
  dav_resource_private *info;
  dav_error            *err;
  const char           *etag;
  char                  buffer[1024];

  /* Null resource */
  if(!resource->exists)
    return NULL;

  info = resource->info;

  /* NS never serve files! Only metadata. */
  if (!resource->collection && !resource->info->metalink) {
    if ((err = dav_ns_get_location(info, r->pool)))
      return err;
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                  "Resource %s located at %s",
                   info->sfn, info->redirect);

    apr_table_setn(r->headers_out, "Location", info->redirect);
#ifdef WITH_METALINK
    snprintf(buffer, sizeof(buffer),
             "<%s://%s%s?metalink>; rel=describedby; type=\"application/metalink+xml\"",
             info->d_conf->redir_scheme, info->request->hostname, info->request->uri);
    apr_table_set(r->err_headers_out, "Link", buffer);
#endif
    return dav_new_error(r->pool, HTTP_MOVED_TEMPORARILY, 0, info->redirect);
  }

  /* Need to redirect? (Missing trailing /) */
  if (info->redirect) {
    apr_table_setn(r->headers_out, "Location", info->redirect);
    return dav_new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0, info->redirect);
  }

  /* Content-type */
  if (resource->info->metalink) {
    ap_set_content_type(r, "application/metalink+xml");
    snprintf(buffer, sizeof(buffer),
             "attachment; filename=\"%s.metalink\"", info->stat.name);
    apr_table_set(r->headers_out, "Content-Disposition", buffer);
  }
  else if (resource->collection) {
    ap_set_content_type(r, "text/html");
  }

  /* Nice thing is, Apache takes care of implementing this */
  apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");

  /* ETag */
  etag = resource->hooks->getetag(resource);
  apr_table_setn(r->headers_out, "ETag", etag);

  /* NS saves the time in seconds since epoch, while Apache expects microseconds */
  ap_update_mtime(r, info->stat.stat.st_mtime * 1000000);
  ap_set_last_modified(r);
    
  return NULL;
}
Example #10
0
AP_DECLARE(int) ap_scan_script_header_err_core(request_rec *r, char *buffer,
                                       int (*getsfunc) (char *, int, void *),
                                       void *getsfunc_data)
{
    char x[MAX_STRING_LEN];
    char *w, *l;
    int p;
    int cgi_status = HTTP_UNSET;
    apr_table_t *merge;
    apr_table_t *cookie_table;

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

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

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

    while (1) {

        int rv = (*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data);
        if (rv == 0) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r,
                          "Premature end of script headers: %s",
                          apr_filepath_name_get(r->filename));
            return HTTP_INTERNAL_SERVER_ERROR;
        }
        else if (rv == -1) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r,
                          "Script timed out before returning headers: %s",
                          apr_filepath_name_get(r->filename));
            return HTTP_GATEWAY_TIME_OUT;
        }

        /* Delete terminal (CR?)LF */

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

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

           /* PR#38070: This fails because it gets confused when a
            * CGI Status header overrides ap_meets_conditions.
            * 
            * We can fix that by dropping ap_meets_conditions when
            * Status has been set.  Since this is the only place
            * cgi_status gets used, let's test it explicitly.
            *
            * The alternative would be to ignore CGI Status when
            * ap_meets_conditions returns anything interesting.
            * That would be safer wrt HTTP, but would break CGI.
            */
            if ((cgi_status == HTTP_UNSET) && (r->method_number == M_GET)) {
                cond_status = ap_meets_conditions(r);
            }
            apr_table_overlap(r->err_headers_out, merge,
                APR_OVERLAP_TABLES_MERGE);
            if (!apr_is_empty_table(cookie_table)) {
                /* the cookies have already been copied to the cookie_table */
                apr_table_unset(r->err_headers_out, "Set-Cookie");
                r->err_headers_out = apr_table_overlay(r->pool,
                    r->err_headers_out, cookie_table);
            }
            return cond_status;
        }

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

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

            for (cp = w; *cp != '\0'; ++cp) {
                native = apr_xlate_conv_byte(ap_hdrs_from_ascii, *cp);
                if (apr_isprint(*cp) && !apr_isprint(native))
                    ++maybeEBCDIC;
                if (!apr_isprint(*cp) && apr_isprint(native))
                    ++maybeASCII;
            }
            if (maybeASCII > maybeEBCDIC) {
                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                             "CGI Interface Error: Script headers apparently ASCII: (CGI = %s)",
                             r->filename);
                inbytes_left = outbytes_left = cp - w;
                apr_xlate_conv_buffer(ap_hdrs_from_ascii,
                                      w, &inbytes_left, w, &outbytes_left);
            }
        }
#endif /*APR_CHARSET_EBCDIC*/
        if (!(l = strchr(w, ':'))) {
            char malformed[(sizeof MALFORMED_MESSAGE) + 1
                           + MALFORMED_HEADER_LENGTH_TO_SHOW];

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

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

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

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

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

            /* Nuke trailing whitespace */

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

            tmp = apr_pstrdup(r->pool, l);
            ap_content_type_tolower(tmp);
            ap_set_content_type(r, tmp);
        }
        /*
         * If the script returned a specific status, that's what
         * we'll use - otherwise we assume 200 OK.
         */
        else if (!strcasecmp(w, "Status")) {
            r->status = cgi_status = atoi(l);
            r->status_line = apr_pstrdup(r->pool, l);
        }
        else if (!strcasecmp(w, "Location")) {
            apr_table_set(r->headers_out, w, l);
        }
        else if (!strcasecmp(w, "Content-Length")) {
            apr_table_set(r->headers_out, w, l);
        }
        else if (!strcasecmp(w, "Content-Range")) {
            apr_table_set(r->headers_out, w, l);
        }
        else if (!strcasecmp(w, "Transfer-Encoding")) {
            apr_table_set(r->headers_out, w, l);
        }
        /*
         * If the script gave us a Last-Modified header, we can't just
         * pass it on blindly because of restrictions on future values.
         */
        else if (!strcasecmp(w, "Last-Modified")) {
            ap_update_mtime(r, apr_date_parse_http(l));
            ap_set_last_modified(r);
        }
        else if (!strcasecmp(w, "Set-Cookie")) {
            apr_table_add(cookie_table, w, l);
        }
        else {
            apr_table_add(merge, w, l);
        }
    }

    return OK;
}
Example #11
0
static apr_status_t ap_xsendfile_output_filter(ap_filter_t *f, apr_bucket_brigade *in) {
  request_rec *r = f->r, *sr = NULL;

  xsendfile_conf_t
    *dconf = (xsendfile_conf_t *)ap_get_module_config(r->per_dir_config, &xsendfile_module),
    *sconf = (xsendfile_conf_t *)ap_get_module_config(r->server->module_config, &xsendfile_module),
    *conf = xsendfile_config_merge(r->pool, sconf, dconf);

  core_dir_config *coreconf = (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);

  apr_status_t rv;
  apr_bucket *e;

  apr_file_t *fd = NULL;
  apr_finfo_t finfo;

  const char *file = NULL;
  char *translated = NULL;

	int errcode;

#ifdef _DEBUG
  ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: output_filter for %s", r->the_request);
#endif
  /*
    should we proceed with this request?

    * sub-requests suck
    * furthermore default-handled requests suck, as they actually shouldn't be able to set headers
  */
  if (
    r->status != HTTP_OK
    || r->main
    || (r->handler && strcmp(r->handler, "default-handler") == 0) /* those table-keys are lower-case, right? */
  ) {
#ifdef _DEBUG
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: not met [%d]", r->status);
#endif
    ap_remove_output_filter(f);
    return ap_pass_brigade(f->next, in);
  }

  /*
    alright, look for x-sendfile
  */
  file = apr_table_get(r->headers_out, AP_XSENDFILE_HEADER);
  apr_table_unset(r->headers_out, AP_XSENDFILE_HEADER);

  /* cgi/fastcgi will put the stuff into err_headers_out */
  if (!file || !*file) {
    file = apr_table_get(r->err_headers_out, AP_XSENDFILE_HEADER);
    apr_table_unset(r->err_headers_out, AP_XSENDFILE_HEADER);
  }

  /* nothing there :p */
  if (!file || !*file) {
#ifdef _DEBUG
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: nothing found");
#endif
    ap_remove_output_filter(f);
    return ap_pass_brigade(f->next, in);
  }

  /*
    drop *everything*
    might be pretty expensive to generate content first that goes straight to the bitbucket,
    but actually the scripts that might set this flag won't output too much anyway
  */
  while (!APR_BRIGADE_EMPTY(in)) {
    e = APR_BRIGADE_FIRST(in);
    apr_bucket_delete(e);
  }
  r->eos_sent = 0;

  rv = ap_xsendfile_get_filepath(r, conf, file, &translated);
  if (rv != OK) {
    ap_log_rerror(
      APLOG_MARK,
      APLOG_ERR,
      rv,
      r,
      "xsendfile: unable to find file: %s",
      file
      );
    ap_remove_output_filter(f);
    ap_die(HTTP_NOT_FOUND, r);
    return HTTP_NOT_FOUND;
  }

#ifdef _DEBUG
  ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: found %s", translated);
#endif

  /*
    ry open the file
  */
  if ((rv = apr_file_open(
    &fd,
    translated,
    APR_READ | APR_BINARY
#if APR_HAS_SENDFILE
    | (coreconf->enable_sendfile == ENABLE_SENDFILE_ON ?  APR_SENDFILE_ENABLED : 0)
#endif
    ,
    0,
    r->pool
  )) != APR_SUCCESS) {
    ap_log_rerror(
      APLOG_MARK,
      APLOG_ERR,
      rv,
      r,
      "xsendfile: cannot open file: %s",
      translated
      );
    ap_remove_output_filter(f);
    ap_die(HTTP_NOT_FOUND, r);
    return HTTP_NOT_FOUND;
  }
#if APR_HAS_SENDFILE && defined(_DEBUG)
  if (coreconf->enable_sendfile != ENABLE_SENDFILE_ON) {
    ap_log_error(
      APLOG_MARK,
      APLOG_WARNING,
      0,
      r->server,
      "xsendfile: sendfile configured, but not active %d",
      coreconf->enable_sendfile
      );
    }
#endif
  /* stat (for etag/cache/content-length stuff) */
  if ((rv = apr_file_info_get(&finfo, APR_FINFO_NORM, fd)) != APR_SUCCESS) {
    ap_log_rerror(
      APLOG_MARK,
      APLOG_ERR,
      rv,
      r,
      "xsendfile: unable to stat file: %s",
      translated
      );
    apr_file_close(fd);
    ap_remove_output_filter(f);
    ap_die(HTTP_FORBIDDEN, r);
    return HTTP_FORBIDDEN;
  }
  /* no inclusion of directories! we're serving files! */
  if (finfo.filetype != APR_REG) {
    ap_log_rerror(
      APLOG_MARK,
      APLOG_ERR,
      APR_EBADPATH,
      r,
      "xsendfile: not a file %s",
      translated
      );
    apr_file_close(fd);
    ap_remove_output_filter(f);
    ap_die(HTTP_NOT_FOUND, r);
    return HTTP_NOT_FOUND;
  }

  /*
    need to cheat here a bit
    as etag generator will use those ;)
    and we want local_copy and cache
  */
  r->finfo.inode = finfo.inode;
  r->finfo.size = finfo.size;

  /*
    caching? why not :p
  */
  r->no_cache = r->no_local_copy = 0;

  /* some script (f?cgi) place stuff in err_headers_out */
  if (
    conf->ignoreLM == XSENDFILE_ENABLED
    || (
      !apr_table_get(r->headers_out, "last-modified")
      && !apr_table_get(r->headers_out, "last-modified")
    )
  ) {
    apr_table_unset(r->err_headers_out, "last-modified");
    ap_update_mtime(r, finfo.mtime);
    ap_set_last_modified(r);
  }
  if (
    conf->ignoreETag == XSENDFILE_ENABLED
    || (
      !apr_table_get(r->headers_out, "etag")
      && !apr_table_get(r->err_headers_out, "etag")
    )
  ) {
    apr_table_unset(r->err_headers_out, "etag");
    ap_set_etag(r);
  }

  apr_table_unset(r->err_headers_out, "content-length");
  ap_set_content_length(r, finfo.size);

  /* as we dropped all the content this field is not valid anymore! */
  apr_table_unset(r->headers_out, "Content-Encoding");
  apr_table_unset(r->err_headers_out, "Content-Encoding");

  /* cache or something? */
  if ((errcode = ap_meets_conditions(r)) != OK) {
#ifdef _DEBUG
    ap_log_error(
      APLOG_MARK,
      APLOG_DEBUG,
      0,
      r->server,
      "xsendfile: met condition %d for %s",
      errcode,
      file
      );
#endif
    apr_file_close(fd);
    r->status = errcode;
  }
  else {
    /* For platforms where the size of the file may be larger than
     * that which can be stored in a single bucket (where the
     * length field is an apr_size_t), split it into several
     * buckets: */
    if (sizeof(apr_off_t) > sizeof(apr_size_t)
        && finfo.size > AP_MAX_SENDFILE) {
        apr_off_t fsize = finfo.size;
        e = apr_bucket_file_create(fd, 0, AP_MAX_SENDFILE, r->pool,
                                   in->bucket_alloc);
        while (fsize > AP_MAX_SENDFILE) {
            apr_bucket *ce;
            apr_bucket_copy(e, &ce);
            APR_BRIGADE_INSERT_TAIL(in, ce);
            e->start += AP_MAX_SENDFILE;
            fsize -= AP_MAX_SENDFILE;
        }
        e->length = (apr_size_t)fsize; /* Resize just the last bucket */
    }
    else {
        e = apr_bucket_file_create(fd, 0, (apr_size_t)finfo.size,
                                   r->pool, in->bucket_alloc);
    }


#if APR_HAS_MMAP
    if (coreconf->enable_mmap == ENABLE_MMAP_ON) {
      apr_bucket_file_enable_mmap(e, 0);
    }
#if defined(_DEBUG)
    else {
      ap_log_error(
        APLOG_MARK,
        APLOG_WARNING,
        0,
        r->server,
        "xsendfile: mmap configured, but not active %d",
        coreconf->enable_mmap
        );
      }
#endif /* _DEBUG */
#endif /* APR_HAS_MMAP */
    APR_BRIGADE_INSERT_TAIL(in, e);
  }

  e = apr_bucket_eos_create(in->bucket_alloc);
  APR_BRIGADE_INSERT_TAIL(in, e);

  /* remove ourselves from the filter chain */
  ap_remove_output_filter(f);

#ifdef _DEBUG
  ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: sending %d bytes", (int)finfo.size);
#endif

  /* send the data up the stack */
  return ap_pass_brigade(f->next, in);
}
Example #12
0
apr_status_t jxr_process_response_headers(request_rec *r, char *buf)
{
	apr_status_t rv = APR_SUCCESS;
	
	apr_size_t pos;
	apr_size_t len;
	char type;
	int nHeaders;
	int i;
	char name[MAX_STRING_LEN];
	char value[MAX_STRING_LEN];
	apr_size_t nlen, vlen;
	table *merge;
	table *cookie_table;
	char *w, *l;
	
	type = jxr_msg_get_type(buf);
	len = jxr_msg_get_length(buf,  &pos);

	if (type != BLOCKTYPE_HTTP_HEADER)
	{
		// Invalid data
		compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: invalid data type (%c) received, while expecting a header (%d)", type, BLOCKTYPE_HTTP_HEADER);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

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

	cookie_table = ap_make_table(r->pool, 2);
    ap_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL);

	nHeaders = jxr_msg_get_int16(buf, &pos);
	for (i=0; i<nHeaders; i++)
	{
		// Process one header -- name -- val
		nlen = jxr_msg_get_string(buf, &pos, name);
		vlen = jxr_msg_get_string(buf, &pos, value);

		w = name;
		l = value;

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

            /* Nuke trailing whitespace */

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

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


	// now merge stuff
	ap_overlap_tables(r->err_headers_out, merge,
        AP_OVERLAP_TABLES_MERGE);
    if (!ap_is_empty_table(cookie_table)) {
        /* the cookies have already been copied to the cookie_table */
        ap_table_unset(r->err_headers_out, "Set-Cookie");
        r->err_headers_out = ap_overlay_tables(r->pool,
            r->err_headers_out, cookie_table);
    }

	return rv;
}
Example #13
0
static int file_cache_handler(request_rec *r)
{
    a_file *match;
    int errstatus;
    int rc = OK;

    /* Bail out if r->handler isn't the default value, and doesn't look like a Content-Type
     * XXX: Even though we made the user explicitly list each path to cache?
     */
    if (ap_strcmp_match(r->handler, "*/*") && !AP_IS_DEFAULT_HANDLER_NAME(r->handler)) {
        return DECLINED;
    }

    /* we don't handle anything but GET */
    if (r->method_number != M_GET) return DECLINED;

    /* did xlat phase find the file? */
    match = ap_get_module_config(r->request_config, &file_cache_module);

    if (match == NULL) {
        return DECLINED;
    }

    /* note that we would handle GET on this resource */
    r->allowed |= (AP_METHOD_BIT << M_GET);

    /* This handler has no use for a request body (yet), but we still
     * need to read and discard it if the client sent one.
     */
    if ((errstatus = ap_discard_request_body(r)) != OK)
        return errstatus;

    ap_update_mtime(r, match->finfo.mtime);

    /* ap_set_last_modified() always converts the file mtime to a string
     * which is slow.  Accelerate the common case.
     * ap_set_last_modified(r);
     */
    {
        apr_time_t mod_time;
        char *datestr;

        mod_time = ap_rationalize_mtime(r, r->mtime);
        if (mod_time == match->finfo.mtime)
            datestr = match->mtimestr;
        else {
            datestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
            apr_rfc822_date(datestr, mod_time);
        }
        apr_table_setn(r->headers_out, "Last-Modified", datestr);
    }

    /* ap_set_content_length() always converts the same number and never
     * returns an error.  Accelerate it.
     */
    r->clength = match->finfo.size;
    apr_table_setn(r->headers_out, "Content-Length", match->sizestr);

    ap_set_etag(r);
    if ((errstatus = ap_meets_conditions(r)) != OK) {
       return errstatus;
    }

    /* Call appropriate handler */
    if (!r->header_only) {
        if (match->is_mmapped == TRUE)
            rc = mmap_handler(r, match);
        else
            rc = sendfile_handler(r, match);
    }

    return rc;
}
Example #14
0
/* The content handler */
static int rcache_handler(request_rec *r)
{
    rcache_info *info;
    info = ap_get_module_config(r->server->module_config, &rcache_module);
    info->data = "";
    info->r = r;
    info->length = 0;
    info->type = "";

    apr_status_t rv;
    const char *retrieve_url;

    if (strcmp(r->handler, "rcache")) {
        rv = DECLINED;
        goto finish;
    }

    // redis context and connection
#ifdef CONN_PERSISTENT
    redisContext *c = info->c;
    redisReply *reply = info->reply;

    if (!c) {
        struct timeval timeout = { 1, 500000 }; // 1.5 seconds
        c = redisConnectWithTimeout(info->hostname, info->port, timeout);
        info->c = c;

        // ping pong test
        if ( !(c == NULL || c->err) ) {
            reply = redisCommand(c,"PING");
#ifdef DEBUG
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "PING: %s", reply->str);
#endif
        }
    }
#else
    redisContext *c;
    redisReply *reply;

    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
    c = redisConnectWithTimeout(info->hostname, info->port, timeout);
#endif

    // when redis connection error
    if (c == NULL || c->err) {
        if (c) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Connection error: %s", c->errstr);
        } else {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Connection error: can't allocate redis context" );
        }
        rv = HTTP_INTERNAL_SERVER_ERROR;
        goto finish;
    }

#ifdef FLAG_WAIT
    int wait = 0;
#endif

    if ( (retrieve_url = apr_table_get(r->subprocess_env, info->env_retrieve_url)) ) {

#ifdef DEBUG
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "%s", r->path_info);
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "%s", retrieve_url);
#endif

#ifdef FLAG_WAIT
        // WAIT flag check.
        reply = redisCommand(c, "GET %s%s", info->prefix_wait, r->path_info);
        if( reply->type != REDIS_REPLY_NIL ) {
            // cache hot-replace check.
            if ( reply->type == REDIS_REPLY_STRING && 0 == strcmp(reply->str,"HOT") ){
                redisCommand(c, "DEL %s%s", info->prefix_wait, r->path_info);
#ifdef DEBUG
                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "hot cache replace: %s", r->path_info );
#endif
                goto gencache;
            }

            // wait cache create.
            wait = 1;
            int loop = 10;
            while(loop){
                reply = redisCommand(c, "GET %s%s", info->prefix_wait, r->path_info);
#ifdef DEBUG
                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "wait loop: remain %d sec", loop);
#endif
                if( reply->type == REDIS_REPLY_NIL ) {
                    goto read;
                }
                sleep(1);
                loop--;
            }
            // when timeup. delete flag.
            redisCommand(c, "DEL %s%s", info->prefix_wait, r->path_info);
            goto gencache;
        }
#endif

read:
        // read from redis.
        reply = redisCommand(c, "HMGET %s%s CONTENT TYPE LENGTH MTIME", info->prefix, r->path_info);
        if( reply->type == REDIS_REPLY_ARRAY ) {
            if ( reply->element[0]->len == 0 ) goto gencache;

            const char* tmp = apr_pstrdup(r->pool, reply->element[1]->str);
            ap_set_content_type(r, tmp);
            ap_set_content_length(r, atoi(reply->element[2]->str) );
            apr_time_t time = atol(reply->element[3]->str);
            ap_update_mtime(r, time);
            ap_set_last_modified(r);
            ap_set_etag(r);

            apr_status_t rc = ap_meets_conditions(r);
            if (rc != OK) {
                rv = rc;
                goto finish;
            }

            if (!r->header_only)
                ap_rputs(reply->element[0]->str, r);

            rv = OK;
            goto finish;
        }
    }else{
        rv = DECLINED;
        goto finish;
    }

gencache:

#ifdef FLAG_WAIT
    if (wait == 0)
        redisCommand(c, "SET %s%s 1", info->prefix_wait, r->path_info);
#endif

    rv = rcache_curl(retrieve_url, info);

    // set content to redis
    if (rv == HTTP_OK) {
        if (strcmp(info->type,""))
            info->type = "text/html";

        if (info->length == 0)
            info->length = strlen(info->data);

        redisCommand(c,"HMSET %s%s CONTENT %s TYPE %s LENGTH %d MTIME %ld",
                info->prefix, r->path_info, info->data, info->type, info->length, info->mtime);

        ap_set_content_type(r, info->type);
        ap_set_content_length(r, info->length);
        ap_update_mtime(r, info->mtime);
        ap_set_last_modified(r);
        ap_set_etag(r);

        if (!r->header_only)
            ap_rputs(info->data, r);
    }
#ifdef FLAG_WAIT
    redisCommand(c, "DEL %s%s", info->prefix_wait, r->path_info);
#endif

finish:
#ifndef CONN_PERSISTENT
    freeReplyObject(reply);
    redisFree(c);
#endif

    return rv;
}
Example #15
0
static int drive_flvx(request_rec *r)
{
    apr_finfo_t fi;
    apr_bucket_brigade *bb;
    apr_off_t offset = 0;
    apr_off_t length = 0;
    apr_file_t *fp = NULL;
    apr_status_t rv = APR_SUCCESS;

    rv = apr_stat(&fi, r->filename, APR_FINFO_SIZE, r->pool);

    if (rv) {
        /* Let the core handle it. */
        return DECLINED;
    }

    /* Open the file */
    rv = apr_file_open(&fp, r->filename, APR_READ,
                       APR_OS_DEFAULT, r->pool);

    if (rv) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                      "file permissions deny server access: %s", r->filename);
        return HTTP_FORBIDDEN;
    }

    offset = get_start(r);

    if (offset != 0 && offset < fi.size) {
        length = fi.size - offset;
    }
    else {
        length = fi.size;

        /* Offset should be reset if invalid mod by Artur Bodera */
        offset = 0;
    }

    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);

    if (offset != 0) {
        length += FLVX_HEADER_LEN;
        rv = apr_brigade_write(bb, NULL, NULL, FLVX_HEADER, FLVX_HEADER_LEN);
        if (rv) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                          "unable to write flv header in brigade");
            return HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    apr_brigade_insert_file(bb, fp, offset, length, r->pool);

    ap_set_content_type(r, "video/x-flv");
    ap_set_content_length(r, length);

    /* Add last-modified headers mod by Artur Bodera */
    ap_update_mtime(r, r->finfo.mtime);
    ap_set_last_modified(r);

    return ap_pass_brigade(r->output_filters, bb);
}
/**
 * SOAP content handler.
 *
 * @return the value that instructs the caller concerning what happened and what to do next.
 *  OK ("we did our thing")
 *  DECLINED ("this isn't something with which we want to get involved")
 *  HTTP_mumble ("an error status should be reported")
 */
static int
gsoap_handler(request_rec * r)
{
    static const int nResponseBufferLen = IOBUF_CHUNK_SIZE;
    const char *pszError = NULL;
    struct soap *psoap = NULL;
    struct apache_soap_interface *pIntf = NULL;
    int nRet = 0;
    char *pszResponse = NULL;
    gsoapConfiguration *pConfig = getConfiguration(r);
    gsoapRequestConfiguration *pRqConf = NULL;

    /*
     * only handle soap requests 
     */
    if (!strstr(r->handler, "soap"))
        return DECLINED;

    /*
     * only handle POST requests 
     */
    if (r->method_number != M_POST && r->method_number != M_GET)
        return DECLINED;

    pszResponse = apr_pcalloc(r->pool, nResponseBufferLen);
    assert(NULL != pConfig);

    psoap = (struct soap *)apr_pcalloc(r->pool, sizeof(struct soap));
    pRqConf = apr_pcalloc(r->pool, sizeof(gsoapRequestConfiguration));
    pszError = SoapSharedLibraries_loadAllLibraries(pConfig->m_pLibraries, r->pool, r);

    pIntf = pConfig->m_pLibraries->m_pIntf;

    ap_update_mtime(r, r->request_time);
    ap_set_last_modified(r);
    if (NULL != pszError)
    {
        static Bool bFirstTime = TRUE;

        if (bFirstTime)
        {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "mod_gsoap: %s", pszError);
            bFirstTime = FALSE;
        }
    }

    /*
     * as a next step, we prepare a buffer that sends the request as first line to gsoap. 
     * Then the remaining data. 
     * We start returning bytes on frecv from this buffer, until it is empty. 
     * then it is not necessary to fiddle around with gsoap's request line parsing.
     */
    if (NULL == pszError)
    {
        pRqConf->r = r;
        pRqConf->headers_sent = FALSE;
        pRqConf->headers_received = FALSE;
        pRqConf->m_pszAllHeaders = NULL;
        pRqConf->m_nHeaderLength = strlen(r->the_request) + 2;
        pRqConf->m_pszCurrentHeaderReadingPosition = NULL;
        pRqConf->m_nOutBufCount = 0;
        pRqConf->m_nOutBufLength = nResponseBufferLen;
        pRqConf->m_pOutBuf = apr_pcalloc(r->pool, nResponseBufferLen);
        pRqConf->http_parse = NULL;
        pRqConf->m_pszAllHeaders = apr_pcalloc(r->pool, pRqConf->m_nHeaderLength + 1);
        pRqConf->m_pszCurrentHeaderReadingPosition = pRqConf->m_pszAllHeaders;
        strcpy(pRqConf->m_pszAllHeaders, r->the_request);
        strcat(pRqConf->m_pszAllHeaders, "\r\n");
        pRqConf->pIntf = pIntf;
    }

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

    /*
     * If we're only supposed to send header information (HEAD request), we're
     * already there.
     */
    if (r->header_only)
    {
        return OK;
    }
    if (NULL != pszError)
    {
        SendErrorMessage(r, pszError);
        return OK;
    }
    nRet = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
    if (OK != nRet)
    {
        SendErrorMessage(r, "Failed to start receiving POST buffer");
        return OK;
    }
    nRet = ap_should_client_block(r);

    /* we check whether this request is HTTP GET or not and handle the GET request */
    if (r->method_number == M_GET)
    {  
	HTTPGet_SendWSDL(r, pConfig->m_pLibraries->m_pSOAPLibrary->m_pszPath);
	return OK;
    }

    if (0 == nRet)
    {
        SendErrorMessage(r, "No body received");
        return OK;
    }

    if (NULL != pszError)
    {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "mod_gsoap: %s", pszError);
        SendErrorMessage(r, pszError);
        return OK;
    }

    if (NULL != pIntf->fsoap_init)
    {
        (*pIntf->fsoap_init) (psoap, r);
        psoap->namespaces = pIntf->namespaces;
        set_callbacks(r, pRqConf, psoap);
        if (NULL != pIntf->fsoap_serve)
        {
            nRet = (*pIntf->fsoap_serve) (psoap, r);
        }
        else
        {
            SendErrorMessage(r, "no soap_serve entry point");
            return OK;
        }
        if (NULL != pIntf->fsoap_destroy)
        {
            pIntf->fsoap_destroy(psoap, r); /* not an error in 2.1.10 anymore */
        }
        if (NULL != pIntf->fsoap_end)
        {
            pIntf->fsoap_end(psoap, r);
        }
        else
        {
            SendErrorMessage(r, "no soap_end entry point");
        }
        if (NULL != pIntf->fsoap_done)
        {
            pIntf->fsoap_done(psoap, r);
        }
        else
        {
            SendErrorMessage(r, "no soap_done entry point");
        }
    }
    else
    {
        SendErrorMessage(r, "no soap_init entry point");
        return OK;
    }

    /*
     * We did what we wanted to do, so tell the rest of the server we
     * succeeded. We need not delete pszResponse, because it was allocated from the request pool.
     */
    return OK;
}
Example #17
0
static int reflector_handler(request_rec * r)
{
    apr_bucket_brigade *bbin, *bbout;
    reflector_cfg *conf;
    apr_status_t status;

    if (strcmp(r->handler, "reflector")) {
        return DECLINED;
    }

    conf = (reflector_cfg *) ap_get_module_config(r->per_dir_config,
                                                  &reflector_module);

    ap_allow_methods(r, 1, "POST", "OPTIONS", NULL);

    if (r->method_number == M_OPTIONS) {
        return ap_send_http_options(r);
    }

    else if (r->method_number == M_POST) {
        const char *content_length, *content_type;
        int seen_eos;

        /*
         * Sometimes we'll get in a state where the input handling has
         * detected an error where we want to drop the connection, so if
         * that's the case, don't read the data as that is what we're trying
         * to avoid.
         *
         * This function is also a no-op on a subrequest.
         */
        if (r->main || r->connection->keepalive == AP_CONN_CLOSE ||
            ap_status_drops_connection(r->status)) {
            return OK;
        }

        /* copy headers from in to out if configured */
        apr_table_do(header_do, r, conf->headers, NULL);

        /* last modified defaults to now, unless otherwise set on the way in */
        if (!apr_table_get(r->headers_out, "Last-Modified")) {
            ap_update_mtime(r, apr_time_now());
            ap_set_last_modified(r);
        }
        ap_set_accept_ranges(r);

        /* reflect the content length, if present */
        if ((content_length = apr_table_get(r->headers_in, "Content-Length"))) {
            apr_off_t offset;

            apr_strtoff(&offset, content_length, NULL, 10);
            ap_set_content_length(r, offset);

        }

        /* reflect the content type, if present */
        if ((content_type = apr_table_get(r->headers_in, "Content-Type"))) {

            ap_set_content_type(r, content_type);

        }

        bbin = apr_brigade_create(r->pool, r->connection->bucket_alloc);
        bbout = apr_brigade_create(r->pool, r->connection->bucket_alloc);

        seen_eos = 0;
        do {
            apr_bucket *bucket;

            status = ap_get_brigade(r->input_filters, bbin, AP_MODE_READBYTES,
                                    APR_BLOCK_READ, HUGE_STRING_LEN);

            if (status != APR_SUCCESS) {
                if (status == AP_FILTER_ERROR) {
                    apr_brigade_destroy(bbin);
                    return status;
                }
                else {
                    apr_brigade_destroy(bbin);
                    return HTTP_BAD_REQUEST;
                }
            }

            for (bucket = APR_BRIGADE_FIRST(bbin);
                 bucket != APR_BRIGADE_SENTINEL(bbin);
                 bucket = APR_BUCKET_NEXT(bucket)) {
                const char *data;
                apr_size_t len;

                if (APR_BUCKET_IS_EOS(bucket)) {
                    seen_eos = 1;
                    break;
                }

                /* These are metadata buckets. */
                if (bucket->length == 0) {
                    continue;
                }

                /*
                 * We MUST read because in case we have an unknown-length
                 * bucket or one that morphs, we want to exhaust it.
                 */
                status = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
                if (status != APR_SUCCESS) {
                    apr_brigade_destroy(bbin);
                    return HTTP_BAD_REQUEST;
                }

                apr_brigade_write(bbout, NULL, NULL, data, len);

                status = ap_pass_brigade(r->output_filters, bbout);
                if (status != APR_SUCCESS) {
                    /* no way to know what type of error occurred */
                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(01410)
                             "reflector_handler: ap_pass_brigade returned %i",
                                  status);
                    return HTTP_INTERNAL_SERVER_ERROR;
                }

            }

            apr_brigade_cleanup(bbin);

        } while (!seen_eos);

        return OK;

    }

    else {
        return HTTP_METHOD_NOT_ALLOWED;
    }

}
Example #18
0
API_EXPORT(int) ap_scan_script_header_err_core(request_rec *r, char *buffer,
				       int (*getsfunc) (char *, int, void *),
				       void *getsfunc_data)
{
    char x[MAX_STRING_LEN];
    char *w, *l;
    int p;
    int cgi_status = HTTP_OK;
    table *merge;
    table *cookie_table;

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

    ap_hard_timeout("read script header", r);

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

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

    while (1) {

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

	/* Delete terminal (CR?)LF */

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

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

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

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

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

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

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

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

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

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

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

	    /* Nuke trailing whitespace */

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

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

	    ap_update_mtime(r, mtime);
	    ap_set_last_modified(r);
	}
	else if (!strcasecmp(w, "Set-Cookie")) {
	    ap_table_add(cookie_table, w, l);
	}
	else {
	    ap_table_add(merge, w, l);
	}
    }
}