static ngx_inline ngx_int_t 
ngx_http_auth_digest_decode_auth(ngx_http_request_t *r, ngx_str_t *auth_str, char *field_name, ngx_str_t *field_val){
  ngx_str_t key;
  u_char *start, *last; //, *p;

  key.len = ngx_strlen(field_name) + 2;
  key.data = ngx_pcalloc(r->pool, key.len);
  // p = ngx_sprintf(key.data,"%s=", field_name);
  
  start = (u_char *) ngx_strstr(auth_str->data, key.data);
  if (start==NULL){
    field_val->len = 1;
    field_val->data = ngx_pcalloc(r->pool, 1);
    return 1;
  }
  
  start += key.len-1;
  if (*start=='"'){
    start++;
    last = (u_char *) ngx_strstr(start+1, "\"");
  }else{
    last = (u_char *) ngx_strstr(start+1, ",");
  }
  if (last==NULL) last = auth_str->data + auth_str->len;
  if (last>start){        
    field_val->len = last-start + 1;
    field_val->data = ngx_pcalloc(r->pool, field_val->len);
    // p = ngx_cpymem(field_val->data, start, last-start);
  }
  
  return 0;
}
static ngx_int_t
ngx_http_static_delete_handler(ngx_http_request_t *r)
{
    u_char                              *last;
    ngx_int_t                            rc;
    ngx_str_t                            filename;
    ngx_str_t                            path;
    size_t                               root;
    ngx_http_static_delete_loc_conf_t   *sdlcf;

    sdlcf = ngx_http_get_module_loc_conf(r, ngx_http_static_delete_module);

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

    rc = ngx_http_discard_request_body(r);
    if (rc != NGX_OK && rc != NGX_AGAIN) {
        return rc;
    }

    rc = ngx_http_complex_value(r, &sdlcf->filename, &filename);
    if (rc != NGX_OK) {
        return NGX_ERROR;
    }

    if (filename.data[filename.len - 1] == '/') {
        return NGX_HTTP_NOT_FOUND;
    }

    if (ngx_strstr(filename.data, "./")) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    if (ngx_strstr(filename.data, "../")) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    last = ngx_http_map_filename_to_path(r, &filename, &path);
    if (last == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    path.len = last - path.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, 
                   "http filename: \"%s\"", path.data);

    if (ngx_delete_file(path.data) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, 
                ngx_delete_file_n " \"%s\" failed", path.data);
        return NGX_HTTP_NOT_FOUND;
    }

    return ngx_http_static_delete_send_response(r, &path);
}
static ngx_int_t
ngx_rtmp_play_parse_index(char type, u_char *args)
{
    u_char             *p, c;
    static u_char       name[] = "xindex=";

    name[0] = (u_char) type;

    for ( ;; ) {
        p = (u_char *) ngx_strstr(args, name);
        if (p == NULL) {
            return 0;
        }

        if (p != args) {
            c = *(p - 1);
            if (c != '?' && c != '&') {
                args = p + 1;
                continue;
            }
        }

        return atoi((char *) p + (sizeof(name) - 1));
    }
}
static ngx_uint_t ngx_http_access_plus_compute_methods(ngx_str_t *str_methods) {
	ngx_uint_t m = NGX_HTTP_UNKNOWN;
	int i = 0;
	ngx_uint_t methods = 0;

	if (ngx_strstr(str_methods->data, "*") || ngx_strstr(str_methods->data, "all")) {
		return ~0;
	}

	do {
		if (ngx_strstr(str_methods->data, ngx_http_access_plus_methods[i])) {
			methods |= m;
		}
		m <<= 1;
	}while (ngx_http_access_plus_methods[++i]);

	return methods;
}
示例#5
0
static void ngx_proc_luashm_backup_thread_cycle(void *data)
{
	ngx_proc_luashm_backup_conf_t  	*pbcf;
    ngx_cycle_t 					*cycle;
    ngx_shm_zone_t   				*zone;
	ngx_str_t 						*name;
	ngx_uint_t 						i;
	ngx_time_t                  	*tp;
    int64_t                     	now,settimestamp;

	cycle = data;
	pbcf = ngx_proc_get_conf(cycle->conf_ctx, ngx_proc_luashm_backup_module);
	if(pbcf->settimestamp.data == NULL){
		pthread_exit((void *)0);
		return;
	}

	while(pbcf->running){
		ngx_time_update();
		if(ngx_strstr(pbcf->settimestamp.data,":")==NULL){
			settimestamp=ngx_atoi(pbcf->settimestamp.data,pbcf->settimestamp.len);
		}else{
			tp = ngx_timeofday();
	    	now = (int64_t) tp->sec * 1000 + tp->msec;
			settimestamp=GetTick((char*)pbcf->settimestamp.data)*1000;
			ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, "========= now:%lu, settimestamp:%lu =========",now,settimestamp);
			if(settimestamp<now)
				settimestamp=(24*60*60*1000)-(now-settimestamp);
			else
				settimestamp=settimestamp-now;

			if(settimestamp==0)settimestamp=1;
		}
		ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, "========= backup time:%s, sleeptime:%lu =========",pbcf->settimestamp.data,settimestamp);

		ngx_msleep(settimestamp);
		if(!pbcf->running)break;

		i = 0;
		for (; i < pbcf->shdict_names->nelts;i++)
		{
			name = ((ngx_str_t*)pbcf->shdict_names->elts)  + i;
			zone = ngx_http_lua_find_zone(name->data,name->len);
			dd("shm.name:%s,shm.name_len:%ld,shm.size:%ld  ", name->data,name->len,zone->shm.size);
			ngx_proc_luashm_backup_backup(cycle,zone);
		}
		ngx_log_error(NGX_LOG_DEBUG, cycle->log, 0, "luashm_backup %V",&ngx_cached_http_time);
		ngx_sleep(60);
		if(!pbcf->running)break;

	}

	pthread_exit((void *)0);
}
static ngx_int_t ngx_streaming_handler(ngx_http_request_t *r) {
  size_t                      root;
  ngx_int_t                   rc;
  ngx_uint_t                  level;
  ngx_str_t                   path;
  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;

  mp4_split_options_t *options = mp4_split_options_init(r);

  if(r->args.len && !mp4_split_options_set(r, options, (const char *)r->args.data, r->args.len)) {
    mp4_split_options_exit(r, options);
    return NGX_DECLINED;
  }

  if(!options) return NGX_DECLINED;

  if(!ngx_http_map_uri_to_path(r, &path, &root, 1)) {
    mp4_split_options_exit(r, options);
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

  u_int m3u8 = 0;

  struct bucket_t *bucket = bucket_init(r);
  int result = 0;
  {
    if(ngx_strstr(path.data, "m3u8")) m3u8 = 1;
    char *ext = strrchr((const char *)path.data, '.');
    strcpy(ext, ".mp4");
    path.len = ((u_char *)ext - path.data) + 4;
    // ngx_open_and_stat_file in ngx_open_cached_file expects the name to be zero-terminated.
    path.data[path.len] = '\0';
  }

  ngx_log_t *nlog = r->connection->log;
  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, nlog, 0, "http mp4 filename: \"%s\"", path.data);

  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 = NGX_MAX_OFF_T_VALUE;
  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) {
    mp4_split_options_exit(r, options);
    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, nlog, of.err,
                    ngx_open_file_n " \"%s\" failed", path.data);
    }

    return rc;
  }

  if(!of.is_file) {
    mp4_split_options_exit(r, options);
    if(ngx_close_file(of.fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno,
                    ngx_close_file_n " \"%s\" failed", path.data);
    }
    return NGX_DECLINED;
  }

  ngx_file_t *file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
  if(file == NULL) {
    mp4_split_options_exit(r, options);
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }
  file->fd = of.fd;
  file->name = path;
  file->log = nlog;

  mp4_context_t *mp4_context = mp4_open(r, file, of.size, MP4_OPEN_MOOV);
  if(!mp4_context) {
    mp4_split_options_exit(r, options);
    ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "mp4_open failed");
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

  mp4_context->root = root;
  if(m3u8) {
    if((result = mp4_create_m3u8(mp4_context, bucket))) {
      char action[50];
      sprintf(action, "ios_playlist&segments=%d", result);
      view_count(mp4_context, (char *)path.data, options ? options->hash : NULL, action);
    }
    r->allow_ranges = 0;
    // dirty hack
    r->headers_out.content_type.data = (u_char *)"application/vnd.apple.mpegurl";
    r->headers_out.content_type.len = 29;
    r->headers_out.content_type_len = r->headers_out.content_type.len;
  } else {
    result = output_ts(mp4_context, bucket, options);
    if(!options || !result) {
      mp4_close(mp4_context);
      ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "output_ts failed");
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    char action[50] = "ios_view";
    view_count(mp4_context, (char *)path.data, options->hash, action);
    r->allow_ranges = 1;
  }

  mp4_close(mp4_context);
  mp4_split_options_exit(r, options);

  result = result == 0 ? 415 : 200;

  r->root_tested = !r->error_page;

  if(result && bucket) {
    nlog->action = "sending mp4 to client";

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, nlog, 0, "content_length: %d", bucket->content_length);
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = bucket->content_length;
    r->headers_out.last_modified_time = of.mtime;
    
    if(ngx_http_set_content_type(r) != NGX_OK) return NGX_HTTP_INTERNAL_SERVER_ERROR;

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

    //ngx_table_elt_t *h = ngx_list_push(&r->headers_out.headers);
    //if(h == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR;

    //h->hash = 1;

    //h->key.len = sizeof(X_MOD_HLS_KEY) - 1;
    //h->key.data = (u_char *)X_MOD_HLS_KEY;
    //h->value.len = sizeof(X_MOD_HLS_VERSION) - 1;
    //h->value.data = (u_char *)X_MOD_HLS_VERSION;

    rc = ngx_http_send_header(r);

    if(rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
      ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n "ngx_http_send_header failed");
      return rc;
    }

    return ngx_http_output_filter(r, bucket->first);
  } else return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
}
ngx_int_t
ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r,
    ngx_http_variable_value_t *v, uintptr_t data)
{
    int                          line_break_len;
    size_t                       size;
    u_char                      *p, *last, *pos;
    ngx_int_t                    i, j;
    ngx_buf_t                   *b, *first = NULL;
    unsigned                     found;
    ngx_connection_t            *c;
    ngx_http_request_t          *mr;
    ngx_http_connection_t       *hc;

    mr = r->main;
    hc = r->main->http_connection;
    c = mr->connection;

    size = 0;
    b = c->buffer;

    if (mr->request_line.data[mr->request_line.len] == CR) {
        line_break_len = 2;

    } else {
        line_break_len = 1;
    }

    if (mr->request_line.data >= b->start
        && mr->request_line.data + mr->request_line.len + line_break_len
           <= b->pos)
    {
        first = b;
        size += b->pos - mr->request_line.data;
    }

    if (hc->nbusy) {
        b = NULL;
        for (i = 0; i < hc->nbusy; i++) {
            b = hc->busy[i];

            if (first == NULL) {
                if (mr->request_line.data >= b->pos
                    || mr->request_line.data + mr->request_line.len
                       + line_break_len <= b->start)
                {
                    continue;
                }

                dd("found first at %d", (int) i);
                first = b;
            }

            size += b->pos - b->start;
        }
    }


    size++;  /* plus the null terminator, as required by the later
                ngx_strstr() call */

    v->data = ngx_palloc(r->pool, size);
    if (v->data == NULL) {
        return NGX_ERROR;
    }

    last = v->data;

    b = c->buffer;
    found = 0;

    if (first == b) {
        found = 1;
        pos = b->pos;

        last = ngx_copy(v->data, mr->request_line.data,
                        pos - mr->request_line.data);

        if (b != mr->header_in) {
            /* skip truncated header entries (if any) */
            while (last > v->data && last[-1] != LF) {
                last--;
            }
        }

        i = 0;
        for (p = v->data; p != last; p++) {
            if (*p == '\0') {
                i++;
                if (p + 1 != last && *(p + 1) == LF) {
                    *p = CR;

                } else if (i % 2 == 1) {
                    *p = ':';

                } else {
                    *p = LF;
                }
            }
        }
    }

    if (hc->nbusy) {
        for (i = 0; i < hc->nbusy; i++) {
            b = hc->busy[i];

            if (!found) {
                if (b != first) {
                    continue;
                }

                dd("found first");
                found = 1;
            }

            p = last;

            pos = b->pos;

            if (b == first) {
                dd("request line: %.*s", (int) mr->request_line.len,
                   mr->request_line.data);

                last = ngx_copy(last,
                                mr->request_line.data,
                                pos - mr->request_line.data);

            } else {
                last = ngx_copy(last, b->start, pos - b->start);
            }

#if 1
            /* skip truncated header entries (if any) */
            while (last > p && last[-1] != LF) {
                last--;
            }
#endif

            j = 0;
            for (; p != last; p++) {
                if (*p == '\0') {
                    j++;
                    if (p + 1 == last) {
                        /* XXX this should not happen */
                        dd("found string end!!");

                    } else if (*(p + 1) == LF) {
                        *p = CR;

                    } else if (j % 2 == 1) {
                        *p = ':';

                    } else {
                        *p = LF;
                    }
                }
            }

            if (b == mr->header_in) {
                break;
            }
        }
    }

    *last++ = '\0';

    if (last - v->data > (ssize_t) size) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "buffer error when evaluating "
                      "$echo_client__request_headers: \"%V\"",
                      (ngx_int_t) (last - v->data - size));

        return NGX_ERROR;
    }

    /* strip the leading part (if any) of the request body in our header.
     * the first part of the request body could slip in because nginx core's
     * ngx_http_request_body_length_filter and etc can move r->header_in->pos
     * in case that some of the body data has been preread into r->header_in.
     */

    if ((p = (u_char *) ngx_strstr(v->data, CRLF CRLF)) != NULL) {
        last = p + sizeof(CRLF CRLF) - 1;

    } else if ((p = (u_char *) ngx_strstr(v->data, CRLF "\n")) != NULL) {
        last = p + sizeof(CRLF "\n") - 1;

    } else if ((p = (u_char *) ngx_strstr(v->data, "\n" CRLF)) != NULL) {
        last = p + sizeof("\n" CRLF) - 1;

    } else {
        for (p = last - 1; p - v->data >= 2; p--) {
            if (p[0] == LF && p[-1] == CR) {
                p[-1] = LF;
                last = p + 1;
                break;
            }

            if (p[0] == LF && p[-1] == LF) {
                last = p + 1;
                break;
            }
        }
    }

    v->len = last - v->data;
    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;

    return NGX_OK;
}
static ngx_int_t
ngx_rtmp_dash_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
{
    u_char                    *p;
    size_t                     len;
    ngx_rtmp_dash_ctx_t       *ctx;
    ngx_rtmp_dash_frag_t      *f;
    ngx_rtmp_dash_app_conf_t  *dacf;

    dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module);
    if (dacf == NULL || !dacf->dash || dacf->path.len == 0) {
        goto next;
    }

    if (s->auto_pushed) {
        goto next;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "dash: publish: name='%s' type='%s'", v->name, v->type);

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module);

    if (ctx == NULL) {
        ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_dash_ctx_t));
        if (ctx == NULL) {
            goto next;
        }
        ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_dash_module);

    } else {
        if (ctx->opened) {
            goto next;
        }

        f = ctx->frags;
        ngx_memzero(ctx, sizeof(ngx_rtmp_dash_ctx_t));
        ctx->frags = f;
    }

    if (ctx->frags == NULL) {
        ctx->frags = ngx_pcalloc(s->connection->pool,
                                 sizeof(ngx_rtmp_dash_frag_t) *
                                 (dacf->winfrags * 2 + 1));
        if (ctx->frags == NULL) {
            return NGX_ERROR;
        }
    }

    ctx->id = 0;

    if (ngx_strstr(v->name, "..")) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "dash: bad stream name: '%s'", v->name);
        return NGX_ERROR;
    }

    ctx->name.len = ngx_strlen(v->name);
    ctx->name.data = ngx_palloc(s->connection->pool, ctx->name.len + 1);

    if (ctx->name.data == NULL) {
        return NGX_ERROR;
    }

    *ngx_cpymem(ctx->name.data, v->name, ctx->name.len) = 0;

    len = dacf->path.len + 1 + ctx->name.len + sizeof(".mpd");
    if (dacf->nested) {
        len += sizeof("/index") - 1;
    }

    ctx->playlist.data = ngx_palloc(s->connection->pool, len);
    p = ngx_cpymem(ctx->playlist.data, dacf->path.data, dacf->path.len);

    if (p[-1] != '/') {
        *p++ = '/';
    }

    p = ngx_cpymem(p, ctx->name.data, ctx->name.len);

    /*
     * ctx->stream holds initial part of stream file path
     * however the space for the whole stream path
     * is allocated
     */

    ctx->stream.len = p - ctx->playlist.data + 1;
    ctx->stream.data = ngx_palloc(s->connection->pool,
                                  ctx->stream.len + NGX_INT32_LEN +
                                  sizeof(".m4x"));

    ngx_memcpy(ctx->stream.data, ctx->playlist.data, ctx->stream.len - 1);
    ctx->stream.data[ctx->stream.len - 1] = (dacf->nested ? '/' : '-');

    if (dacf->nested) {
        p = ngx_cpymem(p, "/index.mpd", sizeof("/index.mpd") - 1);
    } else {
        p = ngx_cpymem(p, ".mpd", sizeof(".mpd") - 1);
    }

    ctx->playlist.len = p - ctx->playlist.data;

    *p = 0;

    /* playlist bak (new playlist) path */

    ctx->playlist_bak.data = ngx_palloc(s->connection->pool,
                                        ctx->playlist.len + sizeof(".bak"));
    p = ngx_cpymem(ctx->playlist_bak.data, ctx->playlist.data,
                   ctx->playlist.len);
    p = ngx_cpymem(p, ".bak", sizeof(".bak") - 1);

    ctx->playlist_bak.len = p - ctx->playlist_bak.data;

    *p = 0;

    ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "dash: playlist='%V' playlist_bak='%V' stream_pattern='%V'",
                   &ctx->playlist, &ctx->playlist_bak, &ctx->stream);

    ctx->start_time = *ngx_cached_time;

    if (ngx_rtmp_dash_ensure_directory(s) != NGX_OK) {
        return NGX_ERROR;
    }

next:
    return next_publish(s, v);
}
static ngx_int_t
ngx_http_upstream_init_consistent(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
{
    ngx_uint_t                              i, j, continuum_index, pointer_index, pointer_per_server, pointer_counter, value;
    ngx_http_upstream_server_t              *server;
    ngx_http_upstream_consistent_peer_t           *peers;
    ngx_http_upstream_consistent_data_t           *ucd;
    ngx_http_upstream_consistent_continuum_item_t *continuum;
    uint64_t                                total_weight;

    us->peer.init = ngx_http_upstream_init_consistent_peer;
    
    ucd = us->peer.data;

    if (!us->servers) {
        return NGX_ERROR;
    }

    server = us->servers->elts;

    peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_peer_t) * us->servers->nelts);

    if (peers == NULL) {
        return NGX_ERROR;
    }

    total_weight = 0;
    for (i = 0; i < us->servers->nelts; i++) {
        peers[i].server = &server[i];
        total_weight += server[i].weight;
    }

    ucd->continuum_count = us->servers->nelts + CONTINUUM_ADDITION;
    
    continuum = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_consistent_continuum_item_t) 
                            * ucd->continuum_count * POINTS_PER_SERVER);
    
    if (continuum == NULL) {
        return NGX_ERROR;
    }

    pointer_counter = continuum_index = 0;

    for (i = 0; i < us->servers->nelts; ++i) {
        float pct = (float)peers[i].server->weight / (float)total_weight;
        pointer_per_server = (ngx_uint_t) ((floorf((float) (pct * POINTS_PER_SERVER / 4 * (float) us->servers->nelts + 0.0000000001))) * 4);
        
        // 4 == pointer_per_hash
        for (pointer_index = 1; pointer_index <= pointer_per_server / 4; pointer_index++) {
            u_char *sort_host;

            sort_host = ngx_pcalloc(cf->pool, MAX_HOST_SORT_LENGTH);
            if (sort_host == NULL) {
                return NGX_ERROR;
            }

            if (ngx_strstr(peers[i].server->addrs->name.data, ":11211") != NULL) {
                 peers[i].server->addrs->name.len -= 6;
                 peers[i].server->addrs->name.data[peers[i].server->addrs->name.len] = '\0';
            }

            ngx_snprintf(sort_host, MAX_HOST_SORT_LENGTH, "%V-%ui%Z", &peers[i].server->addrs->name, pointer_index-1);

            // 4 == pointer_per_hash
            for (j = 0; j < 4; j++) {
                value = ngx_http_upstream_consistent_ketama_hash(sort_host, ngx_strlen(sort_host), j);
                continuum[continuum_index].index = i;
                continuum[continuum_index++].value = value;
            }
        }

        pointer_counter += pointer_per_server;
    }

    ngx_qsort(continuum, pointer_counter, sizeof(ngx_http_upstream_consistent_continuum_item_t), ngx_http_upstream_consistent_continuum_item_cmp);

    ucd->peers = peers;

    ucd->continuum_points_counter = pointer_counter;
    ucd->continuum = continuum;

    /*
    for (i = 0; i < continuum_index; i++) {
        ngx_log_error(NGX_LOG_WARN, cf->log, 0, "upstream_consistent: %i", continuum[i].value);
    }
    */

    return NGX_OK;
}
/*
 * Function called when the sticky command is parsed on the conf file
 */
static char *ngx_http_sticky_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_upstream_srv_conf_t  *upstream_conf;
	ngx_http_sticky_srv_conf_t    *sticky_conf;
	ngx_uint_t i;
	ngx_str_t tmp;
	ngx_str_t name = ngx_string("route");
	ngx_str_t domain = ngx_string("");
	ngx_str_t path = ngx_string("/");
	ngx_str_t hmac_key = ngx_string("");
	time_t expires = NGX_CONF_UNSET;
	unsigned secure = 0;
	unsigned httponly = 0;
	ngx_http_sticky_misc_hash_pt hash = NGX_CONF_UNSET_PTR;
	ngx_http_sticky_misc_hmac_pt hmac = NULL;
	ngx_http_sticky_misc_text_pt text = NULL;
	ngx_uint_t no_fallback = 0;

	/* parse all elements */
	for (i = 1; i < cf->args->nelts; i++) {
		ngx_str_t *value = cf->args->elts;

		/* is "name=" is starting the argument ? */
		if ((u_char *)ngx_strstr(value[i].data, "name=") == value[i].data) {

			/* do we have at least one char after "name=" ? */
			if (value[i].len <= sizeof("name=") - 1) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"name=\"");
				return NGX_CONF_ERROR;
			}

			/* save what's after "name=" */
			name.len = value[i].len - ngx_strlen("name=");
			name.data = (u_char *)(value[i].data + sizeof("name=") - 1);
			continue;
		}

		/* is "domain=" is starting the argument ? */
		if ((u_char *)ngx_strstr(value[i].data, "domain=") == value[i].data) {

			/* do we have at least one char after "domain=" ? */
			if (value[i].len <= ngx_strlen("domain=")) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"domain=\"");
				return NGX_CONF_ERROR;
			}

			/* save what's after "domain=" */
			domain.len = value[i].len - ngx_strlen("domain=");
			domain.data = (u_char *)(value[i].data + sizeof("domain=") - 1);
			continue;
		}

		/* is "path=" is starting the argument ? */
		if ((u_char *)ngx_strstr(value[i].data, "path=") == value[i].data) {

			/* do we have at least one char after "path=" ? */
			if (value[i].len <= ngx_strlen("path=")) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"path=\"");
				return NGX_CONF_ERROR;
			}

			/* save what's after "domain=" */
			path.len = value[i].len - ngx_strlen("path=");
			path.data = (u_char *)(value[i].data + sizeof("path=") - 1);
			continue;
		}

		/* is "expires=" is starting the argument ? */
		if ((u_char *)ngx_strstr(value[i].data, "expires=") == value[i].data) {

			/* do we have at least one char after "expires=" ? */
			if (value[i].len <= sizeof("expires=") - 1) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"expires=\"");
				return NGX_CONF_ERROR;
			}

			/* extract value */
			tmp.len =  value[i].len - ngx_strlen("expires=");
			tmp.data = (u_char *)(value[i].data + sizeof("expires=") - 1);

			/* convert to time, save and validate */
			expires = ngx_parse_time(&tmp, 1);
			if (expires == NGX_ERROR || expires < 1) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value for \"expires=\"");
				return NGX_CONF_ERROR;
			}
			continue;
		}

		if (ngx_strncmp(value[i].data, "secure", 6) == 0 && value[i].len == 6) {
			secure = 1;
			continue;
		}

		if (ngx_strncmp(value[i].data, "httponly", 8) == 0 && value[i].len == 8) {
			httponly = 1;
			continue;
		}

		/* is "text=" is starting the argument ? */
		if ((u_char *)ngx_strstr(value[i].data, "text=") == value[i].data) {

			/* only hash or hmac can be used, not both */
			if (hmac || hash != NGX_CONF_UNSET_PTR) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please choose between \"hash=\", \"hmac=\" and \"text\"");
				return NGX_CONF_ERROR;
			}

			/* do we have at least one char after "name=" ? */
			if (value[i].len <= sizeof("text=") - 1) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"text=\"");
				return NGX_CONF_ERROR;
			}

			/* extract value to temp */
			tmp.len =  value[i].len - ngx_strlen("text=");
			tmp.data = (u_char *)(value[i].data + sizeof("text=") - 1);

			/* is name=raw */
			if (ngx_strncmp(tmp.data, "raw", sizeof("raw") - 1) == 0 ) {
				text = ngx_http_sticky_misc_text_raw;
				continue;
			}

			/* is name=md5 */
			if (ngx_strncmp(tmp.data, "md5", sizeof("md5") - 1) == 0 ) {
				text = ngx_http_sticky_misc_text_md5;
				continue;
			}

			/* is name=sha1 */
			if (ngx_strncmp(tmp.data, "sha1", sizeof("sha1") - 1) == 0 ) {
				text = ngx_http_sticky_misc_text_sha1;
				continue;
			}

			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "wrong value for \"text=\": raw, md5 or sha1");
			return NGX_CONF_ERROR;
		}

		/* is "hash=" is starting the argument ? */
		if ((u_char *)ngx_strstr(value[i].data, "hash=") == value[i].data) {

			/* only hash or hmac can be used, not both */
			if (hmac || text) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please choose between \"hash=\", \"hmac=\" and \"text=\"");
				return NGX_CONF_ERROR;
			}

			/* do we have at least one char after "hash=" ? */
			if (value[i].len <= sizeof("hash=") - 1) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"hash=\"");
				return NGX_CONF_ERROR;
			}

			/* extract value to temp */
			tmp.len =  value[i].len - ngx_strlen("hash=");
			tmp.data = (u_char *)(value[i].data + sizeof("hash=") - 1);

			/* is hash=index */
			if (ngx_strncmp(tmp.data, "index", sizeof("index") - 1) == 0 ) {
				hash = NULL;
				continue;
			}

			/* is hash=md5 */
			if (ngx_strncmp(tmp.data, "md5", sizeof("md5") - 1) == 0 ) {
				hash = ngx_http_sticky_misc_md5;
				continue;
			}

			/* is hash=sha1 */
			if (ngx_strncmp(tmp.data, "sha1", sizeof("sha1") - 1) == 0 ) {
				hash = ngx_http_sticky_misc_sha1;
				continue;
			}

			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "wrong value for \"hash=\": index, md5 or sha1");
			return NGX_CONF_ERROR;
		}

		/* is "hmac=" is starting the argument ? */
		if ((u_char *)ngx_strstr(value[i].data, "hmac=") == value[i].data) {

			/* only hash or hmac can be used, not both */
			if (hash != NGX_CONF_UNSET_PTR || text) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please choose between \"hash=\", \"hmac=\" and \"text\"");
				return NGX_CONF_ERROR;
			}

			/* do we have at least one char after "hmac=" ? */
			if (value[i].len <= sizeof("hmac=") - 1) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"hmac=\"");
				return NGX_CONF_ERROR;
			}

			/* extract value */
			tmp.len =  value[i].len - ngx_strlen("hmac=");
			tmp.data = (u_char *)(value[i].data + sizeof("hmac=") - 1);

			/* is hmac=md5 ? */
			if (ngx_strncmp(tmp.data, "md5", sizeof("md5") - 1) == 0 ) {
				hmac = ngx_http_sticky_misc_hmac_md5;
				continue;
			}

			/* is hmac=sha1 ? */
			if (ngx_strncmp(tmp.data, "sha1", sizeof("sha1") - 1) == 0 ) {
				hmac = ngx_http_sticky_misc_hmac_sha1;
				continue;
			}
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "wrong value for \"hmac=\": md5 or sha1");
			return NGX_CONF_ERROR;
		}

		/* is "hmac_key=" is starting the argument ? */
		if ((u_char *)ngx_strstr(value[i].data, "hmac_key=") == value[i].data) {

			/* do we have at least one char after "hmac_key=" ? */
			if (value[i].len <= ngx_strlen("hmac_key=")) {
				ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"hmac_key=\"");
				return NGX_CONF_ERROR;
			}

			/* save what's after "hmac_key=" */
			hmac_key.len = value[i].len - ngx_strlen("hmac_key=");
			hmac_key.data = (u_char *)(value[i].data + sizeof("hmac_key=") - 1);
			continue;
		}

		/* is "no_fallback" flag present ? */
		if (ngx_strncmp(value[i].data, "no_fallback", sizeof("no_fallback") - 1) == 0 ) {
			no_fallback = 1;
			continue;
		}

		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid arguement (%V)", &value[i]);
		return NGX_CONF_ERROR;
	}

	/* if has and hmac and name have not been set, default to md5 */
	if (hash == NGX_CONF_UNSET_PTR && hmac == NULL && text == NULL) {
		hash = ngx_http_sticky_misc_md5;
	}

	/* don't allow meaning less parameters */
	if (hmac_key.len > 0 && hash != NGX_CONF_UNSET_PTR) {
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"hmac_key=\" is meaningless when \"hmac\" is used. Please remove it.");
		return NGX_CONF_ERROR;
	}

	/* ensure we have an hmac key if hmac's been set */
	if (hmac_key.len == 0 && hmac != NULL) {
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please specify \"hmac_key=\" when using \"hmac\"");
		return NGX_CONF_ERROR;
	}

	/* ensure hash is NULL to avoid conflicts later */
	if (hash == NGX_CONF_UNSET_PTR) {
		hash = NULL;
	}

	/* save the sticky parameters */
	sticky_conf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_sticky_module);
	sticky_conf->cookie_name = name;
	sticky_conf->cookie_domain = domain;
	sticky_conf->cookie_path = path;
	sticky_conf->cookie_expires = expires;
	sticky_conf->cookie_secure = secure;
	sticky_conf->cookie_httponly = httponly;
	sticky_conf->hash = hash;
	sticky_conf->hmac = hmac;
	sticky_conf->text = text;
	sticky_conf->hmac_key = hmac_key;
	sticky_conf->no_fallback = no_fallback;
	sticky_conf->peers = NULL; /* ensure it's null before running */

	upstream_conf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);

	/* 
	 * ensure another upstream module has not been already loaded
	 * peer.init_upstream is set to null and the upstream module use RR if not set
	 * But this check only works when the other module is declared before sticky
	 */
	if (upstream_conf->peer.init_upstream) {
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "You can't use sticky with another upstream module");
		return NGX_CONF_ERROR;
	}

	/* configure the upstream to get back to this module */
	upstream_conf->peer.init_upstream = ngx_http_init_upstream_sticky;

	upstream_conf->flags = NGX_HTTP_UPSTREAM_CREATE
		| NGX_HTTP_UPSTREAM_MAX_FAILS
		| NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
		| NGX_HTTP_UPSTREAM_DOWN
    | NGX_HTTP_UPSTREAM_WEIGHT;

	return NGX_CONF_OK;
}
static int
ngx_http_lua_ngx_req_raw_header(lua_State *L)
{
    int                          n, line_break_len;
    u_char                      *data, *p, *last, *pos;
    unsigned                     no_req_line = 0, found;
    size_t                       size;
    ngx_buf_t                   *b, *first = NULL;
    ngx_int_t                    i, j;
    ngx_connection_t            *c;
    ngx_http_request_t          *r, *mr;
    ngx_http_connection_t       *hc;

    n = lua_gettop(L);
    if (n > 0) {
        no_req_line = lua_toboolean(L, 1);
    }

    dd("no req line: %d", (int) no_req_line);

    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "no request object found");
    }

    ngx_http_lua_check_fake_request(L, r);

    mr = r->main;
    hc = mr->http_connection;
    c = mr->connection;

#if 1
    dd("hc->nbusy: %d", (int) hc->nbusy);

    if (hc->nbusy) {
        dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos,
           hc->busy[0]->last, hc->busy[0]->end);
    }

    dd("request line: %p %p", mr->request_line.data,
       mr->request_line.data + mr->request_line.len);

    dd("header in: %p %p %p %p", mr->header_in->start,
       mr->header_in->pos, mr->header_in->last,
       mr->header_in->end);

    dd("c->buffer: %p %p %p %p", c->buffer->start,
       c->buffer->pos, c->buffer->last,
       c->buffer->end);
#endif

    size = 0;
    b = c->buffer;

    if (mr->request_line.data[mr->request_line.len] == CR) {
        line_break_len = 2;

    } else {
        line_break_len = 1;
    }

    if (mr->request_line.data >= b->start
        && mr->request_line.data + mr->request_line.len
           + line_break_len <= b->pos)
    {
        first = b;
        size += b->pos - mr->request_line.data;
    }

    dd("size: %d", (int) size);

    if (hc->nbusy) {
        b = NULL;
        for (i = 0; i < hc->nbusy; i++) {
            b = hc->busy[i];

            dd("busy buf: %d: [%.*s]", (int) i, (int) (b->pos - b->start),
               b->start);

            if (first == NULL) {
                if (mr->request_line.data >= b->pos
                    || mr->request_line.data
                       + mr->request_line.len + line_break_len
                       <= b->start)
                {
                    continue;
                }

                dd("found first at %d", (int) i);
                first = b;
            }

            dd("adding size %d", (int) (b->pos - b->start));
            size += b->pos - b->start;
        }
    }

    size++;  /* plus the null terminator, as required by the later
                ngx_strstr() call */

    dd("header size: %d", (int) size);

    data = lua_newuserdata(L, size);
    last = data;

    b = c->buffer;
    found = 0;

    if (first == b) {
        found = 1;
        pos = b->pos;

        if (no_req_line) {
            last = ngx_copy(data,
                            mr->request_line.data
                            + mr->request_line.len + line_break_len,
                            pos - mr->request_line.data
                            - mr->request_line.len - line_break_len);

        } else {
            last = ngx_copy(data, mr->request_line.data,
                            pos - mr->request_line.data);
        }

        if (b != mr->header_in) {
            /* skip truncated header entries (if any) */
            while (last > data && last[-1] != LF) {
                last--;
            }
        }

        i = 0;
        for (p = data; p != last; p++) {
            if (*p == '\0') {
                i++;
                if (p + 1 != last && *(p + 1) == LF) {
                    *p = CR;

                } else if (i % 2 == 1) {
                    *p = ':';

                } else {
                    *p = LF;
                }
            }
        }
    }

    if (hc->nbusy) {
        for (i = 0; i < hc->nbusy; i++) {
            b = hc->busy[i];

            if (!found) {
                if (b != first) {
                    continue;
                }

                dd("found first");
                found = 1;
            }

            p = last;

            pos = b->pos;

            if (b == first) {
                dd("request line: %.*s", (int) mr->request_line.len,
                   mr->request_line.data);

                if (no_req_line) {
                    last = ngx_copy(last,
                                    mr->request_line.data
                                    + mr->request_line.len + line_break_len,
                                    pos - mr->request_line.data
                                    - mr->request_line.len - line_break_len);

                } else {
                    last = ngx_copy(last,
                                    mr->request_line.data,
                                    pos - mr->request_line.data);

                }

            } else {
                last = ngx_copy(last, b->start, pos - b->start);
            }

#if 1
            /* skip truncated header entries (if any) */
            while (last > p && last[-1] != LF) {
                last--;
            }
#endif

            j = 0;
            for (; p != last; p++) {
                if (*p == '\0') {
                    j++;
                    if (p + 1 == last) {
                        /* XXX this should not happen */
                        dd("found string end!!");

                    } else if (*(p + 1) == LF) {
                        *p = CR;

                    } else if (j % 2 == 1) {
                        *p = ':';

                    } else {
                        *p = LF;
                    }
                }
            }

            if (b == mr->header_in) {
                break;
            }
        }
    }

    *last++ = '\0';

    if (last - data > (ssize_t) size) {
        return luaL_error(L, "buffer error: %d", (int) (last - data - size));
    }

    /* strip the leading part (if any) of the request body in our header.
     * the first part of the request body could slip in because nginx core's
     * ngx_http_request_body_length_filter and etc can move r->header_in->pos
     * in case that some of the body data has been preread into r->header_in.
     */

    if ((p = (u_char *) ngx_strstr(data, CRLF CRLF)) != NULL) {
        last = p + sizeof(CRLF CRLF) - 1;

    } else if ((p = (u_char *) ngx_strstr(data, CRLF "\n")) != NULL) {
        last = p + sizeof(CRLF "\n") - 1;

    } else if ((p = (u_char *) ngx_strstr(data, "\n" CRLF)) != NULL) {
        last = p + sizeof("\n" CRLF) - 1;

    } else {
        for (p = last - 1; p - data >= 2; p--) {
            if (p[0] == LF && p[-1] == CR) {
                p[-1] = LF;
                last = p + 1;
                break;
            }

            if (p[0] == LF && p[-1] == LF) {
                last = p + 1;
                break;
            }
        }
    }

    lua_pushlstring(L, (char *) data, last - data);
    return 1;
}
static void
ngx_wirte_tracking_into_mongodb(ngx_http_request_t *r,
                                ngx_http_vesb_aio_log_main_conf_t *valcf,ngx_http_vesb_aio_log_loc_conf_t *vallcf,int timeuse)
{
    mongo                     conn[1];
    char                      *conn_str;
    int                       port,status,insertstatus;
    time_t                    timenow;
    ngx_list_part_t 		      *part = &r->headers_in.headers.part;
    ngx_table_elt_t 		      *header = part->elts;
    ngx_uint_t				        i;

    if(r->headers_out.status == NGX_HTTP_OK)
    {
        conn_str = (char *)valcf->mongodb_conn_str.data;
        port = (int)valcf->mongodb_conn_port;
        status = mongo_client( conn, conn_str, port );
        if( status == MONGO_OK ) {
            mongo_set_op_timeout( conn, 10000 );//time oust 10000 ms
            time ( &timenow );
            bson b[1];
            bson_init( b );
            bson_append_new_oid( b, "_id" );

            if( r->headers_in.x_forwarded_for == NULL )
            {
                bson_append_string_n( b, "realclientip" , (char *)r->connection->addr_text.data, r->connection->addr_text.len);
            }
            else
            {
                bson_append_string_n( b, "realclientip" , (char *)r->headers_in.x_forwarded_for->value.data,r->headers_in.x_forwarded_for->value.len);
            }

            bson_append_int( b,"statuscode",r->headers_out.status);
            bson_append_int( b,"usetime",timeuse);
            bson_append_long( b,"requestsize",r->request_length);
            bson_append_long( b,"responsesize",r->headers_out.content_length_n);
            bson_append_time_t( b,"invoketime",timenow );


            if(vallcf->app_name.data != NULL)
            {
                bson_append_string_n( b,"appname",(char *)vallcf->app_name.data,vallcf->app_name.len);
            }
            else
            {
                bson_append_string( b,"appname","undefine");
            }

            /*get method name*/
            for(i=0;/* void */; ++i)
            {
                if(i >= part->nelts)
                {
                    if(part->next == NULL)
                    {
                        break;
                    }

                    part = part->next;
                    header = part->elts;
                    i=0;
                }

                if(header[i].hash == 0)
                {
                    continue;
                }

                if(ngx_strstr(header[i].key.data,"SOAPAction") != NULL)
                {
                    bson_append_string_n( b,"SOAPAction",(char *)header[i].value.data,header[i].value.len);
                }
                else if(ngx_strstr(header[i].key.data,"Content-Type") != NULL)
                {
                    bson_append_string_n( b,"Content-Type",(char *)header[i].value.data,header[i].value.len);
                }
            }


            bson_finish( b );
            insertstatus = mongo_insert( conn,"vesb.tracking", b , NULL );

            if( insertstatus != MONGO_OK ) {
                ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, "insert tracking log in mongodb is failed!(error:%d)",conn[0].err);
            }
            bson_destroy( b );
        }
        else
        {
            ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, "mongodb is unconnection!(error:%d)",status);
        }

        mongo_destroy( conn );

    }
}
static ngx_str_t*
ngx_http_graphicsmagick_get_command(ngx_http_request_t *r)
{
	u_char							*dst, *src;
	size_t							 len;
	u_char							*p, *start_p;
	ngx_uint_t						 i;
	ngx_list_part_t					*part;
	ngx_table_elt_t					*header;
	ngx_str_t						*ret;

	part = &r->headers_in.headers.part;
	header = part->elts;

	for (i = 0; /* void */ ; i++) {

		if (i >= part->nelts) {
			if (part->next == NULL) {
				break;
			}

			part = part->next;
			header = part->elts;
			i = 0;
		}

		if (header[i].key.len == ngx_http_graphicsmagick_command_header.len
			&& ngx_strncmp(header[i].key.data, ngx_http_graphicsmagick_command_header.data,
						   header[i].key.len) == 0) {
			ret = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
			ret->data = header[i].value.data;
			ret->len = header[i].value.len;
			return ret;
		}
	}

	/* not found, check as a reaquest arg */
	if (r->args.len) {
		p = (u_char *) ngx_strstr(r->args.data, "X-ImageMagick-Convert");

		if (p) {
			start_p = p += 22;
			while (p < r->args.data + r->args.len) {
				if (*p++ != '&') {
					continue;
				}
			}

			ret = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
			ret->data = start_p;
			ret->len = p - start_p;
			
			dst = ret->data;
			src = ret->data;

			ngx_unescape_uri(&dst, &src, ret->len, NGX_UNESCAPE_URI);
			
			len = (ret->data + ret->len) - src;
			if (len) {
				dst = ngx_copy(dst, src, len);
			}

			ret->len = dst - ret->data;
		
			return ret;
		}
	}

	return NULL;
}
示例#14
0
static char *
ngx_http_naxsi_cr_loc_conf(ngx_conf_t *cf, ngx_command_t *cmd,
			   void *conf)
{

  ngx_http_dummy_loc_conf_t	*alcf = conf, **bar;  
  ngx_http_dummy_main_conf_t    *main_cf;
  ngx_str_t			*value;
  ngx_http_check_rule_t		*rule_c;
  unsigned int	i;
  u_char			*var_end;

  

  if (!alcf || !cf)
    return (NGX_CONF_ERROR); 
  value = cf->args->elts;
  main_cf = ngx_http_conf_get_module_main_conf(cf, ngx_http_naxsi_module);
  if (!alcf->pushed) { 
    bar = ngx_array_push(main_cf->locations);
    if (!bar)
      return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
    *bar = alcf;
    alcf->pushed = 1;
  }
  
  if (ngx_strcmp(value[0].data, TOP_CHECK_RULE_T) &&
      ngx_strcmp(value[0].data, TOP_CHECK_RULE_N))
    return (NGX_CONF_ERROR);
  
/* #ifdef _debug_readconf */
/*   ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,  */
/* 		     "pushing rule %d in check rules", rule.rule_id);   */
/* #endif */

  i = 0;
  if (!alcf->check_rules)
    alcf->check_rules = ngx_array_create(cf->pool, 2, 
					 sizeof(ngx_http_check_rule_t));
  if (!alcf->check_rules)
    return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
  rule_c = ngx_array_push(alcf->check_rules);
  if (!rule_c) return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
  memset(rule_c, 0, sizeof(ngx_http_check_rule_t));
  /* process the first word : score rule */
  if (value[1].data[i] == '$') {
    var_end = (u_char *) ngx_strchr((value[1].data)+i, ' ');
    if (!var_end) { /* LCOV_EXCL_START */
      ngx_http_dummy_line_conf_error(cf, value);
      return (NGX_CONF_ERROR);
      /* LCOV_EXCL_STOP */
    }
    rule_c->sc_tag.len = var_end - value[1].data;
    rule_c->sc_tag.data = ngx_pcalloc(cf->pool, rule_c->sc_tag.len + 1);
    if (!rule_c->sc_tag.data)
      return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
    memcpy(rule_c->sc_tag.data, value[1].data, rule_c->sc_tag.len);
    i += rule_c->sc_tag.len + 1;
  } else {
    /* LCOV_EXCL_START */
    ngx_http_dummy_line_conf_error(cf, value);
    return (NGX_CONF_ERROR); 
    /* LCOV_EXCL_STOP */
  }
  // move to next word
  while (value[1].data[i] && value[1].data[i] == ' ')
    i++;
  // get the comparison type
  if (value[1].data[i] == '>' && value[1].data[i+1] == '=')
    rule_c->cmp = SUP_OR_EQUAL;
  else if (value[1].data[i] == '>' && value[1].data[i+1] != '=')
    rule_c->cmp = SUP;
  else if (value[1].data[i] == '<' && value[1].data[i+1] == '=')
    rule_c->cmp = INF_OR_EQUAL;
  else if (value[1].data[i] == '<' && value[1].data[i+1] != '=')
    rule_c->cmp = INF;
  else {
    ngx_http_dummy_line_conf_error(cf, value);
    return (NGX_CONF_ERROR);
  }
  // move to next word
  while (value[1].data[i] && !(value[1].data[i] >= '0' && 
			       value[1].data[i] <= '9') && (value[1].data[i] != '-'))
    i++;
  NX_LOG_DEBUG(_debug_readconf,  NGX_LOG_EMERG, cf, 0,
	       "XX-special score in checkrule:%s from (%d)",
	       value[1].data, atoi((const char *)value[1].data+i));
  // get the score
  rule_c->sc_score = atoi((const char *)(value[1].data+i));
  /* process the second word : Action rule */
  if (ngx_strstr(value[2].data, "BLOCK"))
    rule_c->block = 1;
  else if (ngx_strstr(value[2].data,"ALLOW"))
    rule_c->allow = 1;
  else if (ngx_strstr(value[2].data, "LOG"))
    rule_c->log = 1;
  else if (ngx_strstr(value[2].data, "DROP"))
    rule_c->drop = 1;
  else {
    /* LCOV_EXCL_START */
    ngx_http_dummy_line_conf_error(cf, value);
    return (NGX_CONF_ERROR);
    /* LCOV_EXCL_STOP */
  }
  return (NGX_CONF_OK);
}
示例#15
0
static ngx_uint_t
ngx_http_browser(ngx_http_request_t *r, ngx_http_browser_conf_t *cf)
{
    size_t                      len;
    u_char                     *name, *ua, *last, c;
    ngx_str_t                  *ancient;
    ngx_uint_t                  i, version, ver, scale;
    ngx_http_modern_browser_t  *modern;

    if (r->headers_in.user_agent == NULL) {
        if (cf->modern_unlisted_browsers) {
            return NGX_HTTP_MODERN_BROWSER;
        }

        return NGX_HTTP_ANCIENT_BROWSER;
    }

    ua = r->headers_in.user_agent->value.data;
    len = r->headers_in.user_agent->value.len;
    last = ua + len;

    if (cf->modern_browsers) {
        modern = cf->modern_browsers->elts;

        for (i = 0; i < cf->modern_browsers->nelts; i++) {
            name = ua + modern[i].skip;

            if (name >= last) {
                continue;
            }

            name = (u_char *) ngx_strstr(name, modern[i].name);

            if (name == NULL) {
                continue;
            }

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "browser: \"%s\"", name);

            name += modern[i].add;

            if (name >= last) {
                continue;
            }

            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "version: \"%ui\" \"%s\"", modern[i].version, name);

            version = 0;
            ver = 0;
            scale = 1000000;

            while (name < last) {

                c = *name++;

                if (c >= '0' && c <= '9') {
                    ver = ver * 10 + (c - '0');
                    continue;
                }

                if (c == '.') {
                    version += ver * scale;

                    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                                   "version: \"%ui\" \"%ui\"",
                                   modern[i].version, version);

                    if (version > modern[i].version) {
                        return NGX_HTTP_MODERN_BROWSER;
                    }

                    ver = 0;
                    scale /= 100;
                    continue;
                }

                break;
            }

            version += ver * scale;

            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "version: \"%ui\" \"%ui\"",
                           modern[i].version, version);

            if (version >= modern[i].version) {
                return NGX_HTTP_MODERN_BROWSER;
            }

            return NGX_HTTP_ANCIENT_BROWSER;
        }

        if (!cf->modern_unlisted_browsers) {
            return NGX_HTTP_ANCIENT_BROWSER;
        }
    }

    if (cf->netscape4) {
        if (len > sizeof("Mozilla/4.72 ") - 1
            && ngx_strncmp(ua, "Mozilla/", sizeof("Mozilla/") - 1) == 0
            && ua[8] > '0' && ua[8] < '5')
        {
            return NGX_HTTP_ANCIENT_BROWSER;
        }
    }

    if (cf->ancient_browsers) {
        ancient = cf->ancient_browsers->elts;

        for (i = 0; i < cf->ancient_browsers->nelts; i++) {
            if (len >= ancient[i].len
                && ngx_strstr(ua, ancient[i].data) != NULL)
            {
                return NGX_HTTP_ANCIENT_BROWSER;
            }
        }
    }

    if (cf->modern_unlisted_browsers) {
        return NGX_HTTP_MODERN_BROWSER;
    }

    return NGX_HTTP_ANCIENT_BROWSER;
}
示例#16
0
//#define readconf_debug
static char *
ngx_http_dummy_read_conf(ngx_conf_t *cf, ngx_command_t *cmd, 
			 void *conf)
{
  ngx_http_dummy_loc_conf_t	*alcf = conf, **bar;
  
  ngx_http_dummy_main_conf_t	*main_cf;
  ngx_str_t			*value;
  ngx_http_rule_t		rule, *rule_r;
  ngx_http_check_rule_t		*rule_c;
  ngx_http_custom_rule_location_t	*location;
  unsigned int	i;
  u_char			*var_end;
  
#ifdef readconf_debug
  if (cf) {
    value = cf->args->elts;
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "TOP READ CONF %V %V", 
		       &(value[0]), &(value[1]));  
  }
#endif
  if (!alcf || !cf)
    return (NGX_CONF_ERROR); 
  value = cf->args->elts;
  main_cf = ngx_http_conf_get_module_main_conf(cf, ngx_http_naxsi_module);
  if (!alcf->pushed) { 
    bar = ngx_array_push(main_cf->locations);
    if (!bar)
      return (NGX_CONF_ERROR);
    *bar = alcf;
    alcf->pushed = 1;
  }
  /* store denied URL for location */
  if (!ngx_strcmp(value[0].data, TOP_DENIED_URL_T) && value[1].len) {
    alcf->denied_url = ngx_pcalloc(cf->pool, sizeof(ngx_str_t));
    if (!alcf->denied_url)
      return (NGX_CONF_ERROR);
    alcf->denied_url->data = ngx_pcalloc(cf->pool, value[1].len+1);
    if (!alcf->denied_url->data)
      return (NGX_CONF_ERROR);
    memcpy(alcf->denied_url->data, value[1].data, value[1].len);
    alcf->denied_url->len = value[1].len;
    return (NGX_CONF_OK);
  }
  /* it's a flagrule, just a hack to enable/disable mod */
  if (!ngx_strcmp(value[0].data, TOP_ENABLED_FLAG_T)) {
    alcf->enabled = 1;
    return (NGX_CONF_OK);
  }
  /* it's a flagrule, just a hack to enable/disable mod */
  if (!ngx_strcmp(value[0].data, TOP_DISABLED_FLAG_T)) {
    alcf->force_disabled = 1;
    return (NGX_CONF_OK);
  }
  /* it's a flagrule, currently just a hack to enable/disable learning mode */
  if (!ngx_strcmp(value[0].data, TOP_LEARNING_FLAG_T)) {
    alcf->learning = 1;
    return (NGX_CONF_OK);
  }
  if (!ngx_strcmp(value[0].data, TOP_BASIC_RULE_T)) {
#ifdef readconf_debug
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "XX-TOP READ CONF %s", 
		       value[0].data);  
#endif
    memset(&rule, 0, sizeof(ngx_http_rule_t));
    if (ngx_http_dummy_cfg_parse_one_rule(cf, value, &rule, 
					   cf->args->nelts) != NGX_CONF_OK)
      {
	ngx_http_dummy_line_conf_error(cf, value);
	return (NGX_CONF_ERROR);
      }
    /* push in whitelist rules, as it have a whitelist ID array */
    if (rule.wl_id) {
#ifdef readconf_debug
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			 "pushing rule %d in whitelist rules", 
			 rule.rule_id);  
#endif
      if (alcf->whitelist_rules == NULL) {
	alcf->whitelist_rules = ngx_array_create(cf->pool, 2,
						 sizeof(ngx_http_rule_t));
	if (alcf->whitelist_rules == NULL) {
	  return NGX_CONF_ERROR;
	}
      }
      rule_r = ngx_array_push(alcf->whitelist_rules);
      if (!rule_r) {
	return (NGX_CONF_ERROR);
      }
      memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
    }
    /* else push in appropriate ruleset */
    else {
      if (rule.br->headers) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in header rules", 
			   rule.rule_id);  
#endif
	if (alcf->header_rules == NULL)  {
	  alcf->header_rules = ngx_array_create(cf->pool, 2,
						sizeof(ngx_http_rule_t));
	  if (alcf->header_rules == NULL) 
	    return NGX_CONF_ERROR;
	}
	rule_r = ngx_array_push(alcf->header_rules);
	if (!rule_r) return (NGX_CONF_ERROR);
	memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
      }
      /* push in body match rules (POST/PUT) */
      if (rule.br->body || rule.br->body_var) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in body rules", rule.rule_id);  
#endif
	if (alcf->body_rules == NULL) {
	  alcf->body_rules = ngx_array_create(cf->pool, 2,
					      sizeof(ngx_http_rule_t));
	  if (alcf->body_rules == NULL) 
	    return NGX_CONF_ERROR;
	}
	rule_r = ngx_array_push(alcf->body_rules);
	if (!rule_r) return (NGX_CONF_ERROR);
	memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
      }
      /* push in generic rules, as it's matching the URI */
      if (rule.br->url) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in generic rules", 
			   rule.rule_id);  
#endif
	if (alcf->generic_rules == NULL) {
	  alcf->generic_rules = ngx_array_create(cf->pool, 2,
						 sizeof(ngx_http_rule_t));
	  if (alcf->generic_rules == NULL) 
	    return NGX_CONF_ERROR;
	}
	rule_r = ngx_array_push(alcf->generic_rules);
	if (!rule_r) return (NGX_CONF_ERROR);
	memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
      }
      /* push in GET arg rules, but we should push in POST rules too  */
      if (rule.br->args_var || rule.br->args) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in GET rules", rule.rule_id);  
#endif
	if (alcf->get_rules == NULL) {
	  alcf->get_rules = ngx_array_create(cf->pool, 2,
					     sizeof(ngx_http_rule_t));
	  if (alcf->get_rules == NULL) 
	    return NGX_CONF_ERROR;
	}
	rule_r = ngx_array_push(alcf->get_rules);
	if (!rule_r) return (NGX_CONF_ERROR);
	memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
      }
      /* push in custom locations. It's a rule matching a VAR_NAME or an EXACT_URI :
	 - GET_VAR, POST_VAR, URI */
      if (rule.br->custom_location) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in custom_location rules", 
			   rule.rule_id);  
#endif
	location = rule.br->custom_locations->elts;
	for (i = 0; i < rule.br->custom_locations->nelts; i++) {
	  if (location[i].args_var) {
	    if (alcf->get_rules == NULL) {
	      alcf->get_rules = ngx_array_create(cf->pool, 2,
						 sizeof(ngx_http_rule_t));
	      if (alcf->get_rules == NULL) 
		return NGX_CONF_ERROR;
	    }
	    rule_r = ngx_array_push(alcf->get_rules);
	    if (!rule_r) return (NGX_CONF_ERROR);
	    memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
	  }
	  if (location[i].body_var) {
	    if (alcf->body_rules == NULL) {
	      alcf->body_rules = ngx_array_create(cf->pool, 2,
						  sizeof(ngx_http_rule_t));
	      if (alcf->body_rules == NULL) 
		return NGX_CONF_ERROR;
	    }
	    rule_r = ngx_array_push(alcf->body_rules);
	    if (!rule_r) return (NGX_CONF_ERROR);
	    memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
		      
	  }
	  if (location[i].headers_var) {
	    if (alcf->header_rules == NULL) {
	      alcf->header_rules = ngx_array_create(cf->pool, 2,
						    sizeof(ngx_http_rule_t));
	      if (alcf->header_rules == NULL) 
		return NGX_CONF_ERROR;
	    }
	    rule_r = ngx_array_push(alcf->header_rules);
	    if (!rule_r) return (NGX_CONF_ERROR);
	    memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
	  }
	}
      }
    }
    return (NGX_CONF_OK);
  }
  /* this should be moved in a function, plus this code is not safe. */
  else if (!ngx_strcmp(value[0].data, TOP_CHECK_RULE_T)) {
#ifdef readconf_debug
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
		       "pushing rule %d in check rules", rule.rule_id);  
#endif
    i = 0;
    if (!alcf->check_rules)
      alcf->check_rules = ngx_array_create(cf->pool, 2, 
					   sizeof(ngx_http_check_rule_t));
    if (!alcf->check_rules)
      return (NGX_CONF_ERROR);
    rule_c = ngx_array_push(alcf->check_rules);
    if (!rule_c) return (NGX_CONF_ERROR);
    memset(rule_c, 0, sizeof(ngx_http_check_rule_t));
    /* process the first word : score rule */
    if (value[1].data[i] == '$') {
#ifdef MDBG
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "XX-special score rule !");
#endif
	var_end = (u_char *) ngx_strchr((value[1].data)+i, ' ');
	if (!var_end) {
	  ngx_http_dummy_line_conf_error(cf, value);
	  return (NGX_CONF_ERROR);
	}
	rule_c->sc_tag.data = ngx_pcalloc(cf->pool, var_end - value[1].data +1);
	if (!rule_c->sc_tag.data)
	  return (NGX_CONF_ERROR);
	memcpy(rule_c->sc_tag.data, value[1].data, (var_end - value[1].data));
	i += (var_end - value[1].data) + 1;
	rule_c->sc_tag.len = (var_end - value[1].data);
      }
    else {
      ngx_http_dummy_line_conf_error(cf, value);
      return (NGX_CONF_ERROR);
    }
    // move to next word
    while (value[1].data[i] && value[1].data[i] == ' ')
      i++;
    // get the comparison type
    if (value[1].data[i] == '>' && value[1].data[i+1] == '=')
      rule_c->cmp = SUP_OR_EQUAL;
    else if (value[1].data[i] == '>' && value[1].data[i+1] != '=')
      rule_c->cmp = SUP;
    else if (value[1].data[i] == '<' && value[1].data[i+1] == '=')
      rule_c->cmp = INF_OR_EQUAL;
    else if (value[1].data[i] == '<' && value[1].data[i+1] != '=')
      rule_c->cmp = INF;
    else {
      ngx_http_dummy_line_conf_error(cf, value);
      return (NGX_CONF_ERROR);
    }
    // move to next word
    while (value[1].data[i] && !(value[1].data[i] >= '0' && 
				 value[1].data[i] <= '9') && (value[1].data[i] != '-'))
      i++;
#ifdef readconf_debug
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
		       "XX-special score in checkrule:%s from (%d)", 
		       value[1].data, atoi((const char *)value[1].data+i));
#endif
    // get the score
    rule_c->sc_score = atoi((const char *)(value[1].data+i));
    /* process the second word : Action rule */
    if (!ngx_strstr(value[2].data, "BLOCK"))
      rule_c->block = 1;
    else if (!ngx_strstr(value[2].data, "ALLOW"))
      rule_c->block = 1;
    else if (!ngx_strstr(value[2].data, "LOG"))
      rule_c->block = 1;
    else {
      ngx_http_dummy_line_conf_error(cf, value);
      return (NGX_CONF_ERROR);
    }
    return (NGX_CONF_OK);
  }
  ngx_http_dummy_line_conf_error(cf, value);
  return (NGX_CONF_ERROR);
}
static ngx_int_t
ngx_http_data_dome_auth_execute_x_datadome_headers(ngx_pool_t *pool, const char* x_datadome_header, ngx_list_t *src, ngx_list_t *dst)
{
  u_char           *end;
  ngx_str_t         x_datadome_headers;
  ngx_uint_t        i, j;
  ngx_list_part_t  *part, *sub_part;
  ngx_table_elt_t  *header, *sub_header, *new_header;

  ngx_uint_t x_datadome_header_len = strlen(x_datadome_header);

  part = &src->part;
  header = part->elts;

  x_datadome_headers.len = 0;
  x_datadome_headers.data = NULL;

  for (i = 0; /* void */ ; i++) {

    if (i >= part->nelts) {
      if (part->next == NULL) {
	    break;
      }

      part = part->next;
      header = part->elts;
      i = 0;
    }

    if (header[i].hash == 0) {
      continue;
    }

    if (header[i].key.len != x_datadome_header_len) {
      continue;
    }

    if (ngx_strncmp(header[i].key.data, x_datadome_header, header[i].key.len) != 0) {
      continue;
    }

    x_datadome_headers.len = header[i].value.len;
    x_datadome_headers.data = ngx_pcalloc(pool, x_datadome_headers.len + 1);
    if (x_datadome_headers.data == NULL) {
        return NGX_ERROR;
    }

    (void) ngx_cpymem(x_datadome_headers.data, header[i].value.data, x_datadome_headers.len);

    break;
  }

  while (x_datadome_headers.len > 0) {

      end = (u_char *) ngx_strstr(x_datadome_headers.data, " ");
      if (end == NULL) {
        end = x_datadome_headers.data + x_datadome_headers.len;
      }

      part = &src->part;
      header = part->elts;

      for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {
            if (part->next == NULL) {
            	break;
            }

            part = part->next;
            header = part->elts;
            i = 0;
        }

        if (header[i].hash == 0) {
          continue;
        }

        if (header[i].key.len != (size_t) (end - x_datadome_headers.data)) {
          continue;
        }

        if (ngx_strncmp(header[i].key.data, x_datadome_headers.data, header[i].key.len) != 0) {
          continue;
        }

        sub_part = &dst->part;
        sub_header = sub_part->elts;

        new_header = NULL;

        for (j = 0; /* void */ ; j++) {
            if (j >= sub_part->nelts) {
                if (sub_part->next == NULL) {
                    break;
                }

                sub_part = sub_part->next;
                sub_header = sub_part->elts;
                j = 0;
            }

            if (sub_header[j].hash == 0) {
              continue;
            }

            if (sub_header[j].key.len != header[i].key.len) {
              continue;
            }

            if (ngx_strncmp(sub_header[j].key.data, header[i].key.data, sub_header[j].key.len) != 0) {
              continue;
            }

            if (sub_header[j].key.len == sizeof("Set-Cookie") - 1 &&
                ngx_strncmp(sub_header[j].key.data, "Set-Cookie", sub_header[j].key.len) == 0) {
                break;
            }

            new_header = &sub_header[j];
            break;
        }

        if (new_header == NULL) {
            new_header = ngx_list_push(dst);
            if (new_header == NULL) {
                return NGX_ERROR;
            }
        }

        new_header->hash = 1;
        new_header->key = header[i].key;
        new_header->value = header[i].value;
        new_header->lowcase_key = header[i].lowcase_key;

        break;
      }

      x_datadome_headers.len -= end - x_datadome_headers.data;
      x_datadome_headers.data = end;
      while (*x_datadome_headers.data == ' ') {
        x_datadome_headers.data++;
        x_datadome_headers.len--;
      }

  }

  return NGX_OK;
}