コード例 #1
0
static ngx_int_t
ngx_tcp_process_http_header(ngx_tcp_lua_http_parse_ctx_t *r,
    ngx_buf_t *b, lua_State *L)
{
    ngx_int_t                       rc;
    size_t                          header_name_len;                        
    size_t                          header_len;                        

    for ( ;; ) {

        rc = ngx_tcp_parse_http_header_line(r, b, 1);

        if (rc == NGX_OK) {

            /* a header line has been parsed successfully */

            header_name_len = r->header_name_end - r->header_name_start;
            header_len = r->header_end - r->header_start;

            lua_pushlstring(L, (const char*)r->header_name_start, header_name_len);
            lua_pushlstring(L, (const char*)r->header_start, header_len);
            lua_rawset(L, -3);
            
            if (0 == ngx_strncasecmp(r->header_name_start, (u_char *) "content-length", header_name_len)
                || 0 == ngx_strncasecmp(r->header_name_start, (u_char *) "content_length", header_name_len) ) {
                r->content_length_n = ngx_atoof(r->header_start, header_len);
            }
            
            if ( (0 == ngx_strncasecmp(r->header_name_start, (u_char *) "transfer-encoding", header_name_len)
                || 0 == ngx_strncasecmp(r->header_name_start, (u_char *) "transfer-encoding", header_name_len) )
                &&  ngx_strlcasestrn(r->header_start, r->header_end, (u_char *) "chunked", 7 - 1) != NULL ) {
                r->chunked = 1;
            }

            continue;
        }

        if (rc == NGX_TCP_HTTP_PARSE_HEADER_DONE) {

            /* a whole header has been parsed successfully */

            //ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
            //               "http proxy header done");

            return NGX_OK;
        }

        if (rc == NGX_AGAIN) {
            return NGX_AGAIN;
        }

        //rc = NGX_HTTP_PARSE_INVALID_HEADER
        /* there was error while a header line parsing */

        //ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
        //              "upstream sent invalid header");
        r->error_code = NGX_TCP_LUA_SOCKET_ERR_HEADERS;
        return NGX_ERROR;
    }
}
コード例 #2
0
static off_t
ngx_http_parallel_get_instance_length(ngx_str_t *content_range, ngx_log_t* log)
{
	u_char* last_slash;
	off_t content_length;

	last_slash = ngx_http_parallel_memrchr(
		content_range->data, '/', content_range->len);
	if (last_slash == NULL)
	{
		ngx_log_error(NGX_LOG_ERR, log, 0,
			"ngx_http_parallel_get_instance_length: "
			"no slash in content-range value \"%V\"", content_range);
		return -1;
	}

	content_length = ngx_atoof(
		last_slash + 1, 
		content_range->data + content_range->len - last_slash - 1);
	if (content_length < 0)
	{
		ngx_log_error(NGX_LOG_ERR, log, 0,
			"ngx_http_parallel_get_instance_length: failed to parse "
			"instance length from content-range \"%V\"", content_range);
		return -1;
	}

	return content_length;
}
コード例 #3
0
static ngx_int_t
ngx_http_redis_process_header(ngx_http_request_t *r)
{
    u_char                         *p;//, *start;
    //ngx_str_t                       line;
    //ngx_uint_t                      flags;
    //ngx_table_elt_t                *h;
    ngx_http_upstream_t            *u;
    //ngx_http_redis_ctx_t       *ctx;
    //ngx_http_redis_loc_conf_t  *mlcf;

    u = r->upstream;

    for (p = u->buffer.pos; p < u->buffer.last; p++) {
        if (*p == LF) {
            goto found;
        }
    }

    return NGX_AGAIN;

found:

    *p = '\0';
    switch (u->buffer.pos[0]) {
        case '+':
        case '-':
        case ':':
            u->headers_in.content_length_n = p - u->buffer.pos - 1;
            u->headers_in.status_n = 200;
            u->state->status = 200;
            return NGX_OK;
        case '$':
            {
                u->headers_in.content_length_n = ngx_atoof(u->buffer.pos + 1, p - u->buffer.pos - 2);
                if (u->headers_in.content_length_n == -1) {
                    u->headers_in.status_n = 404;
                    u->state->status = 404;
                }else {
                    u->headers_in.status_n = 200;
                    u->state->status = 200;
                    u->buffer.pos = p + 1;
                }
            } 
    }

    return NGX_OK;
    /*
no_valid:

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "redis sent invalid response: \"%V\"", &line);

    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
    */
}
コード例 #4
0
static ngx_int_t
ngx_http_poller_process_header(ngx_http_request_t *r)
{
  static ngx_str_t      content_length = ngx_string("Content-Length");
  ngx_http_poller_t    *poller;
  ngx_http_upstream_t  *u;
  ngx_int_t             rc;
  ngx_str_t             name;
  ngx_str_t             value;

  poller = ngx_http_get_module_ctx(r, ngx_http_poller_module);
  if (poller == NULL) {
    return NGX_ERROR;
  }

  u = r->upstream;

  for ( ;; ) {
    rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);

    if (rc == NGX_OK) {
      name.len = r->header_name_end - r->header_name_start;
      name.data = r->header_name_start;

      value.len = r->header_end - r->header_start;
      value.data = r->header_start;

      if (name.len == content_length.len &&
          ngx_strncasecmp(name.data, content_length.data, name.len) == 0) {
        u->headers_in.content_length_n = ngx_atoof(value.data, value.len);
      }

      if (poller->handler.header != NULL) {
	poller->handler.header(r, &name, &value);
      }

      continue;
    }

    if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
      return NGX_OK;
    }

    if (rc == NGX_AGAIN) {
      return NGX_AGAIN;
    }

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "upstream sent invalid header");

    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  }
}
コード例 #5
0
ファイル: ngx_parse.c プロジェクト: loverlucia/nginx-1.9.6
//指定空间时,可以使用多种单位
//默认(不指定)为B(b)
off_t
ngx_parse_offset(ngx_str_t *line)
{
    u_char  unit;
    off_t   offset, scale, max;
    size_t  len;

    len = line->len;
    unit = line->data[len - 1];

    switch (unit) {
    case 'K':
    case 'k':
        len--;
        max = NGX_MAX_OFF_T_VALUE / 1024;
        scale = 1024;
        break;

    case 'M':
    case 'm':
        len--;
        max = NGX_MAX_OFF_T_VALUE / (1024 * 1024);
        scale = 1024 * 1024;
        break;

    case 'G':
    case 'g':
        len--;
        max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024);
        scale = 1024 * 1024 * 1024;
        break;

    default:
        max = NGX_MAX_OFF_T_VALUE;
        scale = 1;
    }

    offset = ngx_atoof(line->data, len);
    if (offset == NGX_ERROR || offset > max) {
        return NGX_ERROR;
    }

    offset *= scale;

    return offset;
}
コード例 #6
0
static ngx_int_t
ngx_http_srcache_process_content_length(ngx_http_request_t *r,
    ngx_table_elt_t *h, ngx_uint_t offset)
{
    ngx_table_elt_t  *ho;

    ho = ngx_list_push(&r->headers_out.headers);
    if (ho == NULL) {
        return NGX_ERROR;
    }

    *ho = *h;

    r->headers_out.content_length = ho;
    r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len);

    return NGX_OK;
}
コード例 #7
0
ファイル: ngx_parse.c プロジェクト: Wushaowei001/omnibus
off_t
ngx_parse_offset(ngx_str_t *line)
{
    u_char     unit;
    off_t      offset;
    size_t     len;
    ngx_int_t  scale;

    len = line->len;
    unit = line->data[len - 1];

    switch (unit) {
    case 'K':
    case 'k':
        len--;
        scale = 1024;
        break;

    case 'M':
    case 'm':
        len--;
        scale = 1024 * 1024;
        break;

    case 'G':
    case 'g':
        len--;
        scale = 1024 * 1024 * 1024;
        break;

    default:
        scale = 1;
    }

    offset = ngx_atoof(line->data, len);
    if (offset == NGX_ERROR) {
        return NGX_ERROR;
    }

    offset *= scale;

    return offset;
}
static ngx_int_t
ngx_http_memcached_hash_process_header(ngx_http_request_t *r)
{
    u_char                         *p, *start;
    ngx_str_t                       line;
    ngx_uint_t                      flags;
    ngx_table_elt_t                *h;
    ngx_http_upstream_t            *u;
    ngx_http_memcached_hash_ctx_t       *ctx;
    ngx_http_memcached_hash_loc_conf_t  *mlcf;

    u = r->upstream;

    for (p = u->buffer.pos; p < u->buffer.last; p++) {
        if (*p == LF) {
            goto found;
        }
    }

    return NGX_AGAIN;

found:

    *p = '\0';

    line.len = p - u->buffer.pos - 1;
    line.data = u->buffer.pos;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "memcached hash: \"%V\"", &line);

    p = u->buffer.pos;

    ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_hash_module);
    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_hash_module);

    if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) {

        p += sizeof("VALUE ") - 1;

        if (ngx_strncmp(p, ctx->key.data, ctx->key.len) != 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "memcached sent invalid key in response \"%V\" "
                          "for key \"%V\"",
                          &line, &ctx->key);

            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
        }

        p += ctx->key.len;

        if (*p++ != ' ') {
            goto no_valid;
        }

        /* flags */
        
        start = p;

        while (*p) {
            if (*p++ == ' ') {
                if (mlcf->gzip_flag) {
                    goto flags;
                } else {
                    goto length;
                }
            }
        }

        goto no_valid;

    flags:
    
        flags = ngx_atoi(start, p - start - 1);
    
        if (flags == (ngx_uint_t) NGX_ERROR) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "memcached sent invalid flags in response \"%V\" "
                          "for key \"%V\"",
                          &line, &ctx->key);
            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
        }
    
        if (flags & mlcf->gzip_flag) {
            h = ngx_list_push(&r->headers_out.headers);
            if (h == NULL) {
                return NGX_ERROR;
            }
    
            h->hash = 1;
            h->key.len = sizeof("Content-Encoding") - 1;
            h->key.data = (u_char *) "Content-Encoding";
            h->value.len = sizeof("gzip") - 1;
            h->value.data = (u_char *) "gzip";
    
            r->headers_out.content_encoding = h;
        }

    length:

        start = p;
        
        while (*p && *p++ != CR) { /* void */ }

        r->headers_out.content_length_n = ngx_atoof(start, p - start - 1);
        if (r->headers_out.content_length_n == -1) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "memcached sent invalid length in response \"%V\" "
                          "for key \"%V\"",
                          &line, &ctx->key);
            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
        }

        u->headers_in.status_n = 200;
        u->state->status = 200;
        u->buffer.pos = p + 1;

        return NGX_OK;
    }

    if (ngx_strcmp(p, "END\x0d") == 0) {
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "key: \"%V\" was not found by memcached", &ctx->key);

        u->headers_in.status_n = 404;
        u->state->status = 404;

        return NGX_OK;
    }

no_valid:

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "memcached sent invalid response: \"%V\"", &line);

    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
コード例 #9
0
ngx_int_t
ngx_stream_upm_process_resp_header(ngx_stream_session_t *s)
{
    ngx_int_t                           rc;
    ngx_array_t                         *resp_headers;
    ngx_table_elt_t                     *h;
    ngx_stream_upm_ctx_t                *ctx;
    ngx_stream_upstream_t               *u;
    //ngx_stream_upm_main_conf_t           *ummcf;
    //ngx_http_upstream_header_t          *hh;
    //ngx_stream_upstream_srv_conf_t      *umcf;
    ngx_stream_upm_resp_header_ctx_t     hctx;
    
    //ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module);
    ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module);

    u = s->upstream;
    resp_headers = ctx->resp_headers;
    if (resp_headers == NULL) {
        resp_headers = ngx_array_create(ctx->pool, 4, sizeof(ngx_table_elt_t));
        if (resp_headers == NULL) {
            return NGX_ERROR;
        }
        ctx->resp_headers = resp_headers;
    }
    ngx_memzero(&hctx, sizeof(ngx_stream_upm_resp_header_ctx_t));

    for ( ;; ) {

        rc = ngx_stream_upm_parse_header_line(&hctx, &u->upstream_buf, 1);

        if (rc == NGX_OK) {

            /* a header line has been parsed successfully */

            h = ngx_array_push(resp_headers);
            if (h == NULL) {
                return NGX_ERROR;
            }

            h->hash = hctx.header_hash;

            h->key.len = hctx.header_name_end - hctx.header_name_start;
            h->value.len = hctx.header_end - hctx.header_start;

            h->key.data = hctx.header_name_start;
            h->value.data = hctx.header_start;

            /*No need to care lowcase_key
            if (h->key.len == r->lowcase_index) {
                ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
            } else {
                ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
            }*/

            ngx_log_debug2(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
                           "stream header: \"%V: %V\"",
                           &h->key, &h->value);

            if (h->key.len == 14 && ngx_strncmp(h->key.data, "Content-Length", h->key.len) == 0) {
                ctx->content_length_n = ngx_atoof(h->value.data, h->value.len);
            }

            if (h->key.len == 17 && ngx_strncmp(h->key.data, "Transfer-Encoding", h->key.len) == 0) {
                if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
                         (u_char *) "chunked", 7 - 1) != NULL) {
                    ctx->chunked = 1;
                }
            }
            continue;
        }

        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

            /* a whole header has been parsed successfully */
            ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
                           "stream upm header done");

            /* Get content length */
            u = s->upstream;

            if (ctx->chunked) {
                ctx->content_length_n = -1;
            }

            /*
             * set u->keepalive if response has no body; this allows to keep
             * connections alive in case of r->header_only or X-Accel-Redirect
             */
            return NGX_DONE;
        }

        if (rc == NGX_AGAIN) {
            return NGX_AGAIN;
        }

        /* there was error while a header line parsing */

        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "upm upstream sent invalid header");

        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
    }
}
コード例 #10
0
static ngx_int_t
ngx_http_flv_handler(ngx_http_request_t *r)
{
    u_char                    *last;
    off_t                      start, len;
    size_t                     root;
    ngx_int_t                  rc;
    ngx_uint_t                 level, i;
    ngx_str_t                  path, value;
    ngx_log_t                 *log;
    ngx_buf_t                 *b;
    ngx_chain_t                out[2];
    ngx_open_file_info_t       of;
    ngx_http_core_loc_conf_t  *clcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    if (r->uri.data[r->uri.len - 1] == '/') {
        return NGX_DECLINED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    if (last == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    log = r->connection->log;

    path.len = last - path.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                   "http flv filename: \"%V\"", &path);

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    ngx_memzero(&of, sizeof(ngx_open_file_info_t));

    of.read_ahead = clcf->read_ahead;
    of.directio = clcf->directio;
    of.valid = clcf->open_file_cache_valid;
    of.min_uses = clcf->open_file_cache_min_uses;
    of.errors = clcf->open_file_cache_errors;
    of.events = clcf->open_file_cache_events;

    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
        != NGX_OK)
    {
        switch (of.err) {

        case 0:
            return NGX_HTTP_INTERNAL_SERVER_ERROR;

        case NGX_ENOENT:
        case NGX_ENOTDIR:
        case NGX_ENAMETOOLONG:

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_NOT_FOUND;
            break;

        case NGX_EACCES:

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_FORBIDDEN;
            break;

        default:

            level = NGX_LOG_CRIT;
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            break;
        }

        if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
            ngx_log_error(level, log, of.err,
                          "%s \"%s\" failed", of.failed, path.data);
        }

        return rc;
    }

    if (!of.is_file) {

        if (ngx_close_file(of.fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", path.data);
        }

        return NGX_DECLINED;
    }

    r->root_tested = !r->error_page;

    start = 0;
    len = of.size;
    i = 1;

    if (r->args.len) {

        if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) {

            start = ngx_atoof(value.data, value.len);

            if (start == NGX_ERROR || start >= len) {
                start = 0;
            }

            if (start) {
                len = sizeof(ngx_flv_header) - 1 + len - start;
                i = 0;
            }
        }
    }

    log->action = "sending flv to client";

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = len;
    r->headers_out.last_modified_time = of.mtime;

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (i == 0) {
        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b->pos = ngx_flv_header;
        b->last = ngx_flv_header + sizeof(ngx_flv_header) - 1;
        b->memory = 1;

        out[0].buf = b;
        out[0].next = &out[1];
    }


    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
    if (b->file == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->allow_ranges = 1;

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    b->file_pos = start;
    b->file_last = of.size;

    b->in_file = b->file_last ? 1: 0;
    b->last_buf = 1;
    b->last_in_chain = 1;

    b->file->fd = of.fd;
    b->file->name = path;
    b->file->log = log;
    b->file->directio = of.is_directio;

    out[1].buf = b;
    out[1].next = NULL;

    return ngx_http_output_filter(r, &out[i]);
}
コード例 #11
0
ファイル: ngx_lua_http.c プロジェクト: alemic/ngx_lua_module
static ngx_int_t
ngx_lua_http_parse_headers(ngx_lua_http_ctx_t *ctx)
{
    u_char            *p, ch;
    ngx_int_t          rc;
    ngx_str_t          str;
    ngx_keyval_t      *header;
    ngx_lua_thread_t  *thr;

    ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
                   "lua http parse headers");

    for ( ;; ) {

        rc = ngx_lua_http_parse_header_line(ctx);

        if (rc != NGX_OK) {
            return rc;
        }

        ngx_log_debug2(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
                      "header name:%*s value:%*s",
                       ctx->header_name_end - ctx->header_name_start,
                       ctx->header_name_start,
                       ctx->header_end - ctx->header_start,
                       ctx->header_start);

        /* TODO */

        if (ctx->content_length == 0
            && ngx_strncmp(ctx->header_name_start, "Content-Length",
                           sizeof("Content-Length") - 1)
               == 0)
        {
            ctx->content_length = ngx_atoof(ctx->header_start,
                                           ctx->header_end - ctx->header_start);
            if (ctx->content_length == NGX_ERROR) {
                return NGX_ERROR;
            }
        }

        thr = ctx->thr;

        if (ctx->thr == NULL) {
            continue;
        }

        for (p = ctx->header_name_start; p < ctx->header_name_end - 1; p++) {
            ch = *p;

            if (ch >= 'A' && ch <= 'Z') {
                ch |= 0x20;

            } else if (ch == '-') {
                ch = '_';
            }

            *p = ch;
        }

        *ctx->header_name_end = '\0';

        header = ngx_array_push(&ctx->headers);
        if (header == NULL) {
            return NGX_ERROR;
        }

        str.len = ctx->header_name_end - ctx->header_name_start + 1;
        str.data = ctx->header_name_start;

        header->key.len = str.len;
        header->key.data = ngx_pstrdup(ctx->pool, &str);

        str.len = ctx->header_end - ctx->header_start;
        str.data = ctx->header_start;

        header->value.len = str.len;
        header->value.data = ngx_pstrdup(ctx->pool, &str);
    }
}
コード例 #12
0
static ngx_int_t
ngx_http_slice_handler(ngx_http_request_t *r)
{
    u_char                    *last;
    off_t                      begin, end, len;
    size_t                     root;
    ngx_int_t                  rc;
    ngx_uint_t                 level, i;
    ngx_str_t                  path, value;
    ngx_log_t                 *log;
    ngx_buf_t                 *b;
    ngx_chain_t                out[3];
    ngx_open_file_info_t       of;
    ngx_http_core_loc_conf_t  *clcf;
    ngx_http_slice_loc_conf_t *slcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    if (r->uri.data[r->uri.len - 1] == '/') {
        return NGX_DECLINED;
    }

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_module);

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    if (last == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    log = r->connection->log;

    path.len = last - path.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                   "http slice filename: \"%V\"", &path);

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    ngx_memzero(&of, sizeof(ngx_open_file_info_t));

    of.read_ahead = clcf->read_ahead;
    of.directio = clcf->directio;
    of.valid = clcf->open_file_cache_valid;
    of.min_uses = clcf->open_file_cache_min_uses;
    of.errors = clcf->open_file_cache_errors;
    of.events = clcf->open_file_cache_events;

    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
        != NGX_OK)
    {
        switch (of.err) {

        case 0:
            return NGX_HTTP_INTERNAL_SERVER_ERROR;

        case NGX_ENOENT:
        case NGX_ENOTDIR:
        case NGX_ENAMETOOLONG:

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_NOT_FOUND;
            break;

        case NGX_EACCES:

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_FORBIDDEN;
            break;

        default:

            level = NGX_LOG_CRIT;
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            break;
        }

        if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
            ngx_log_error(level, log, of.err,
                          "%s \"%s\" failed", of.failed, path.data);
        }

        return rc;
    }

    if (!of.is_file) {

        if (ngx_close_file(of.fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", path.data);
        }

        return NGX_DECLINED;
    }

    r->root_tested = !r->error_page;

    begin = 0;
    end = of.size;

    if (r->args.len) {

        if (ngx_http_arg(r, slcf->begin.data, slcf->begin.len, &value)
            == NGX_OK)
        {
            begin = ngx_atoof(value.data, value.len);

            if (begin == NGX_ERROR || begin >= of.size) {
                begin = 0;
            }
        }

        if (ngx_http_arg(r, slcf->end.data, slcf->end.len, &value) == NGX_OK) {

            end = ngx_atoof(value.data, value.len);

            if (end == NGX_ERROR || end >= of.size) {
                end = of.size;
            }
        }
    }

    end = end < begin ? of.size : end;

    len = (end == begin) ? 0 : ((end - begin)
            + ((begin == 0 && slcf->header_first) ? slcf->header.len : 0)
            + ((end == of.size && slcf->footer_last) ? slcf->footer.len : 0));

    log->action = "sending slice to client";

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = len;
    r->headers_out.last_modified_time = of.mtime;

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (len == 0) {
        r->header_only = 1;
        return ngx_http_send_header(r);
    }

    /*
     * add header when the first header is not denied
     */
    if (slcf->header.len
        && !(begin == 0 && !slcf->header_first))
    {
        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b->pos = slcf->header.data;
        b->last = slcf->header.data + slcf->header.len;
        b->memory = 1;

        out[0].buf = b;
        out[0].next = &out[1];

        i = 0;
    } else {
        i = 1;
    }

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
    if (b->file == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->allow_ranges = 1;

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    b->file_pos = begin;
    b->file_last = end;

    b->in_file = b->file_last ? 1: 0;
    b->last_buf = 1;
    b->last_in_chain = 1;

    b->file->fd = of.fd;
    b->file->name = path;
    b->file->log = log;
    b->file->directio = of.is_directio;

    out[1].buf = b;
    out[1].next = NULL;

    /*
     * add footer when the last footer is not denied
     */
    if (slcf->footer.len
        && !(end == of.size && !slcf->footer_last))
    {
        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b->pos = slcf->footer.data;
        b->last = slcf->footer.data + slcf->footer.len;
        b->memory = 1;
        b->last_buf = 1;
        b->last_in_chain = 1;

        out[2].buf = b;
        out[2].next = NULL;

        out[1].buf->last_buf = 0;
        out[1].buf->last_in_chain = 0;
        out[1].next = &out[2];
    }

    return ngx_http_output_filter(r, &out[i]);
}
コード例 #13
0
static ngx_inline ngx_int_t
ngx_http_modsecurity_save_headers_in(ngx_http_request_t *r)
{
    ngx_http_modsecurity_ctx_t  *ctx;

    ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);

    /* clean up headers_in */
    ngx_memzero(&r->headers_in, sizeof(ngx_http_headers_in_t));

    if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
                      sizeof(ngx_table_elt_t))
            != NGX_OK)
    {
        return NGX_ERROR;
    }


    if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,
                       sizeof(ngx_table_elt_t *))
            != NGX_OK)
    {
        return NGX_ERROR;
    }

    r->headers_in.content_length_n = -1;
    r->headers_in.keep_alive_n = -1;

    r->headers_in.headers.part.nelts = 0;
    r->headers_in.headers.part.next = NULL;
    r->headers_in.headers.last = &r->headers_in.headers.part;

    /* shadow copy */
    if (apr_table_do(ngx_http_modsecurity_save_headers_in_visitor,
                     r, ctx->req->headers_in, NULL) == 0) {

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "ModSecurity: save headers in error");

        return NGX_ERROR;
    }

    if (r->headers_in.content_length) {
        r->headers_in.content_length_n =
            ngx_atoof(r->headers_in.content_length->value.data,
                      r->headers_in.content_length->value.len);

        if (r->headers_in.content_length_n == NGX_ERROR) {
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                          "ModSecurity: invalid \"Content-Length\" header");
            return NGX_ERROR;
        }
    }

    if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) {
        if (r->headers_in.keep_alive) {
            r->headers_in.keep_alive_n =
                ngx_atotm(r->headers_in.keep_alive->value.data,
                          r->headers_in.keep_alive->value.len);
        }
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "ModSecurity: save headers in done");

    return NGX_OK;
}
コード例 #14
0
static ngx_int_t
ngx_http_memcached_process_header(ngx_http_request_t *r) {
	u_char                          *p, *start;
	ngx_str_t                        line;
	ngx_uint_t                       flags;
	ngx_table_elt_t                 *h;
	ngx_http_upstream_t             *u;
	ngx_http_memcached_ctx_t        *ctx;
	ngx_http_memcached_loc_conf_t   *mlcf;

	for (u = r->upstream, p = u->buffer.pos; p < u->buffer.last; ++p) {
		if (*p == LF) goto found;
	}
	return NGX_AGAIN;

found:

	line.data = u->buffer.pos;
	u->buffer.pos = p + 1; /* eat */
	if (*--p != CR) goto no_valid;
	*p = '\0';
	line.len = p - line.data;

	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		"memcached: \"%V\"", &line);

	ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);
	mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);

	p = line.data;
	switch (ctx->type) {
	case NGX_HTTP_MEMCACHED_SET:
	case NGX_HTTP_MEMCACHED_DEL:
	case NGX_HTTP_MEMCACHED_CAS:
		if (!ngx_strcmp(p, "STORED")) {
			ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
				"key: \"%V\" was stored by memcached", &ctx->key);

			NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "200 STORED");
			return NGX_OK;
		}
		if (!ngx_strcmp(p, "NOT_STORED")) {
			ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
				"key: \"%V\" was not found by memcached", &ctx->key);

			NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "404 NOT_STORED");
			return NGX_OK;
		}
		if (!ngx_strcmp(p, "NOT_FOUND")) {
			ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
				"key: \"%V\" was not found by memcached", &ctx->key);

			NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "404 NOT_FOUND");
			return NGX_OK;
		}
		if (!ngx_strcmp(p, "DELETED")) {
			ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
				"key: \"%V\" was deleted by memcached", &ctx->key);

			NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "200 DELETED");
			return NGX_OK;
		}
		if (!ngx_strcmp(p, "EXISTS")) {
			ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
				"key: \"%V\" was not found by memcached", &ctx->key);

			NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "406 EXISTS");
			return NGX_OK;
		}
		break;
	case NGX_HTTP_MEMCACHED_GET:
		/* VALUE <key> <flags> <bytes> */
		if (!ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1)) {
			p += sizeof("VALUE ") - 1;

			if (ngx_strncmp(p, ctx->key.data, ctx->key.len)) {
				ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
					"memcached sent invalid key in response \"%V\" "
					"for key \"%V\"",
					&line, &ctx->key);

				return NGX_HTTP_UPSTREAM_INVALID_HEADER;
			}

			if (*(p += ctx->key.len) != ' ') goto no_valid;

			/* flags */
			for (start = ++p; *p;) {
				if (*p++ == ' ') {
					/*if (mlcf->gzip_flag)*/ goto flags;
					/*else goto length;*/
				}
			}
			goto no_valid;

		flags:
			if (!(h = ngx_list_push(&r->headers_out.headers)))
				return NGX_ERROR;
			h->hash = 1;
			ngx_str_set(&h->key, "Memcached-Flags");
			h->value.data = start;
			h->value.len = p - 1 - start;

			/* gzip flags for data */
			flags = ngx_atoi(start, p - 1 - start);
			if (flags == (ngx_uint_t)NGX_ERROR) {
				ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
					"memcached sent invalid flags in response \"%V\" "
					"for key \"%V\"",
					&line, &ctx->key);
				return NGX_HTTP_UPSTREAM_INVALID_HEADER;
			}

			if (flags & mlcf->gzip_flag) {
				if (!(h = ngx_list_push(&r->headers_out.headers)))
					return NGX_ERROR;
				h->hash = 1;
				ngx_str_set(&h->key, "Content-Encoding");
				ngx_str_set(&h->value, "gzip");

				r->headers_out.content_encoding = h;
			}

		/*length:*/
			for (start = p; *p && *p != ' '; ++p);

			u->headers_in.content_length_n = ngx_atoof(start, p - start);
			if (u->headers_in.content_length_n == -1) {
				ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
					"memcached sent invalid length in response \"%V\" "
					"for key \"%V\"",
					&line, &ctx->key);
				return NGX_HTTP_UPSTREAM_INVALID_HEADER;
			}

		/*unique:*/
			if (*p) {
				if (!(h = ngx_list_push(&r->headers_out.headers)))
					return NGX_ERROR;
				h->hash = 1;
				ngx_str_set(&h->key, "Memcached-Unique");
				h->value.data = ++p;
				h->value.len = line.data + line.len - p;
			}

		/*value:*/
			if (mlcf->value_flag) {
				u->process_header = ngx_http_memcached_process_value;
				return ngx_http_memcached_process_value(r);
			}

			u->headers_in.status_n = u->state->status = 200;
			ngx_str_set(&u->headers_in.status_line, "200 OK");
			return NGX_OK;
		}

		if (!ngx_strcmp(p, "END")) {
			ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
				"key: \"%V\" was not found by memcached", &ctx->key);

			NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "404 NOT_FOUND");
			return NGX_OK;
		}
	}
no_valid:

	ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
		"memcached sent invalid response: \"%V\"", &line);

	return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
コード例 #15
0
static ngx_int_t
ngx_lua_http_btt_parse_args(ngx_http_request_t *r, ngx_btt_ctx_t *ctx)
{
    size_t   nlen, vlen;
    u_char  *p, *last, *name, *val, *dst, *src;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "lua http btt parse args");

    if (r->args.len == 0) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "invalid uri \"%V\"", &r->args);
        return NGX_ERROR;
    }

    p = r->args.data;
    last = p + r->args.len;

    for ( /* void */ ; p < last; p++) {

        name = p;

        p = ngx_strlchr(p, last, '&');

        if (p == NULL) {
            p = last;
        }

        val = ngx_strlchr(name, p, '=');

        if (val == NULL) {
            val = p;
        }

        nlen = val - name;
        vlen = (++val < p) ? p - val : 0;

        dst = ngx_pnalloc(r->pool, vlen);
        if (dst == NULL) {
            return NGX_ERROR;
        }

        src = val;
        val = dst;
        ngx_unescape_uri(&dst, &src, vlen, 0);
        vlen = dst - val;

        ngx_log_debug4(NGX_LOG_ALERT, r->connection->log, 0,
                       "%*s=%*s", nlen, name, vlen, val);

        /*
         * BT Client:
         *
         *   BitComet: localip, natmapped, port_type
         *   NetTransport: supportcrypto
         *   uTorrent: corrupt
         *   XunLei: ip
         */

        switch (nlen) {

        case 2:

            if (ngx_strncmp(name, "ip", nlen) == 0) {
                ctx->internal_ip = ngx_inet_addr(val, vlen);
                if (ctx->internal_ip == INADDR_NONE) {
                    goto invalid;
                }
                break;
            }

            break;

        case 3:

            if (ngx_strncmp(name, "key", nlen) == 0) {
                ngx_memcpy(ctx->key, val, vlen);
                break;
            }

            break;

        case 4:

            if (ngx_strncmp(name, "port", nlen) == 0) {
                ctx->internal_port = (in_port_t) ngx_atoi(val, vlen);
                if (ctx->internal_port == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "left", nlen) == 0) {
                ctx->left = ngx_atoof(val, vlen);
                if (ctx->left == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        case 5:

            if (ngx_strncmp(name, "event", nlen) == 0) {

                if (ngx_strncmp(val, "none", sizeof("none") - 1) == 0) {
                    ctx->event = NGX_BTT_EVENT_NONE;

                } else if (ngx_strncmp(val, "completed",
                                       sizeof("completed") - 1)
                           == 0)
                {
                    ctx->event = NGX_BTT_EVENT_COMPLETED;

                } else if (ngx_strncmp(val, "started", sizeof("started") - 1)
                           == 0)
                {
                    ctx->event = NGX_BTT_EVENT_STARTED;

                } else if (ngx_strncmp(val, "stopped", sizeof("stopped") - 1)
                           == 0)
                {
                    ctx->event = NGX_BTT_EVENT_STOPPED;

                } else {
                    goto invalid;
                }

                break;
            }

            break;

        case 7:

            if (ngx_strncmp(name, "peer_id", nlen) == 0) {
                ngx_memcpy(ctx->peer_id, val, vlen);
                break;
            }

            if (ngx_strncmp(name, "localip", nlen) == 0) {
                ctx->internal_ip = ngx_inet_addr(val, vlen);
                if (ctx->internal_ip == INADDR_NONE) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "numwant", nlen) == 0) {
                ctx->numwant = ngx_atoi(val, vlen);
                if (ctx->numwant == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "compact", nlen) == 0) {
                ctx->compact = ngx_atoi(val, vlen);
                if (ctx->compact == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "corrupt", nlen) == 0) {
                ctx->corrupt = ngx_atoi(val, vlen);
                if (ctx->corrupt == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        case 8:

            if (ngx_strncmp(name, "uploaded", nlen) == 0) {
                ctx->uploaded = ngx_atoof(val, vlen);
                if (ctx->uploaded == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        case 9:

            if (ngx_strncmp(name, "info_hash ", nlen) == 0) {
                ngx_memcpy(ctx->info_hash, val, vlen);
                break;
            }

            if (ngx_strncmp(name, "natmapped ", nlen) == 0) {
                ctx->natmapped = ngx_atoi(val, vlen);
                if (ctx->natmapped == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "port_type", nlen) == 0) {
                ngx_memcpy(ctx->port_type, val, vlen);
                break;
            }

            break;

        case 10:

            if (ngx_strncmp(name, "downloaded", nlen) == 0) {
                ctx->downloaded = ngx_atoof(val, vlen);
                if (ctx->downloaded == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            if (ngx_strncmp(name, "no_peer_id ", nlen) == 0) {
                ctx->no_peer_id = ngx_atoi(val, vlen);
                if (ctx->no_peer_id == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        case 13:

            if (ngx_strncmp(name, "supportcrypto", nlen) == 0) {
                ctx->supportcrypto = ngx_atoi(val, vlen);
                if (ctx->supportcrypto == NGX_ERROR) {
                    goto invalid;
                }
                break;
            }

            break;

        default:
            break;
        }
    }

    return NGX_OK;

invalid:

    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                  "invalid value \"%*s\" of the key \"%*s\"",
                  nlen, name, vlen, val);

    return NGX_ERROR;
}
コード例 #16
0
static ngx_int_t
ngx_http_redis_process_header(ngx_http_request_t *r)
{
    u_char                    *p, *len;
    ngx_str_t                  line;
    ngx_http_upstream_t       *u;
    ngx_http_redis_ctx_t      *ctx;

    u = r->upstream;

    for (p = u->buffer.pos; p < u->buffer.last; p++) {
        if (*p == LF) {
            goto found;
        }
    }

    return NGX_AGAIN;

found:

    *p = '\0';

    line.len = p - u->buffer.pos - 1;
    line.data = u->buffer.pos;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "redis: \"%V\"", &line);

    p = u->buffer.pos;

    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    if (ngx_strcmp(p, "-ERR") == 0) {
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "error was received from redis");

        u->headers_in.status_n = 404;
        u->state->status = 404;

        return NGX_OK;
    }

    if (ngx_strcmp(p, "+OK\x0d") == 0) {
        p += sizeof("+OK") - 1 + sizeof(CRLF) - 1;
    }

    if (ngx_strcmp(p, "$-1\x0d") == 0) {
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "key: \"%V\" was not found by redis", &ctx->key);

        u->headers_in.status_n = 404;
        u->state->status = 404;

        return NGX_OK;
    }

    if (ngx_strncmp(p, "$", sizeof("$") - 1) == 0) {

        p += sizeof("$") - 1;

        len = p;

        while (*p && *p++ != CR) { /* void */ }

        r->headers_out.content_length_n = ngx_atoof(len, p - len - 1);
        if (r->headers_out.content_length_n == -1) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "redis sent invalid length in response \"%V\" "
                          "for key \"%V\"",
                          &line, &ctx->key);
            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
        }

        u->headers_in.status_n = 200;
        u->state->status = 200;
        u->buffer.pos = p + 1;

        return NGX_OK;
    }

no_valid:

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "redis sent invalid response: \"%V\"", &line);

    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
コード例 #17
0
static ngx_int_t
ngx_http_memcached_process_header(ngx_http_request_t *r)
{
    u_char                    *p, *len;
    ngx_str_t                  line;
    ngx_http_upstream_t       *u;
    ngx_http_memcached_ctx_t  *ctx;

    u = r->upstream;

    for (p = u->buffer.pos; p < u->buffer.last; p++) {
        if (*p == LF) {
            goto found;
        }
    }

    return NGX_AGAIN;

found:

    *p = '\0';

    line.len = p - u->buffer.pos - 1;
    line.data = u->buffer.pos;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "memcached: \"%V\"", &line);

    p = u->buffer.pos;

    ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);

    if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) {

        p += sizeof("VALUE ") - 1;

        if (ngx_strncmp(p, ctx->key.data, ctx->key.len) != 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "memcached sent invalid key in response \"%V\" "
                          "for key \"%V\"",
                          &line, &ctx->key);

            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
        }

        p += ctx->key.len;

        if (*p++ != ' ') {
            goto no_valid;
        }

        /* skip flags */

        while (*p) {
            if (*p++ == ' ') {
                goto length;
            }
        }

        goto no_valid;

    length:

        len = p;

        while (*p && *p++ != CR) { /* void */ }

        r->headers_out.content_length_n = ngx_atoof(len, p - len - 1);
        if (r->headers_out.content_length_n == -1) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "memcached sent invalid length in response \"%V\" "
                          "for key \"%V\"",
                          &line, &ctx->key);
            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
        }

        u->headers_in.status_n = 200;
        u->state->status = 200;
        u->buffer.pos = p + 1;

        return NGX_OK;
    }

    if (ngx_strcmp(p, "END\x0d") == 0) {
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                      "key: \"%V\" was not found by memcached", &ctx->key);

        u->headers_in.status_n = 404;
        u->state->status = 404;

        return NGX_OK;
    }

no_valid:

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "memcached sent invalid response: \"%V\"", &line);

    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}