Beispiel #1
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;

}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
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);
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
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);
	}
    }
}
Beispiel #8
0
static int req_meets_conditions(lua_State*L )
{
  request_rec *r = CHECK_REQUEST_OBJECT(1);
  lua_pushnumber(L, ap_meets_conditions(r));
  return 1;
}