Line data Source code
1 :
2 : /*
3 : * Copyright (C) Yichun Zhang (agentzh)
4 : */
5 :
6 :
7 : #ifndef DDEBUG
8 : #define DDEBUG 0
9 : #endif
10 : #include "ddebug.h"
11 :
12 :
13 : #include <nginx.h>
14 : #include "ngx_http_lua_headers_in.h"
15 : #include "ngx_http_lua_util.h"
16 : #include <ctype.h>
17 :
18 :
19 : static ngx_int_t ngx_http_set_header(ngx_http_request_t *r,
20 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
21 : static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r,
22 : ngx_http_lua_header_val_t *hv, ngx_str_t *value,
23 : ngx_table_elt_t **output_header);
24 : static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r,
25 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
26 : static ngx_int_t ngx_http_set_user_agent_header(ngx_http_request_t *r,
27 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
28 : static ngx_int_t ngx_http_set_connection_header(ngx_http_request_t *r,
29 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
30 : static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r,
31 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
32 : static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r,
33 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
34 : static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r,
35 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
36 : static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r,
37 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
38 : static ngx_int_t ngx_http_lua_validate_host(ngx_str_t *host, ngx_pool_t *pool,
39 : ngx_uint_t alloc);
40 : static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r,
41 : ngx_http_lua_header_val_t *hv, ngx_str_t *value);
42 : static ngx_int_t ngx_http_lua_rm_header_helper(ngx_list_t *l,
43 : ngx_list_part_t *cur, ngx_uint_t i);
44 :
45 :
46 : static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = {
47 : { ngx_string("Host"),
48 : offsetof(ngx_http_headers_in_t, host),
49 : ngx_http_set_host_header },
50 :
51 : { ngx_string("Connection"),
52 : offsetof(ngx_http_headers_in_t, connection),
53 : ngx_http_set_connection_header },
54 :
55 : { ngx_string("If-Modified-Since"),
56 : offsetof(ngx_http_headers_in_t, if_modified_since),
57 : ngx_http_set_builtin_header },
58 :
59 : #if defined(nginx_version) && nginx_version >= 9002
60 : { ngx_string("If-Unmodified-Since"),
61 : offsetof(ngx_http_headers_in_t, if_unmodified_since),
62 : ngx_http_set_builtin_header },
63 : #endif
64 :
65 : #if defined(nginx_version) && nginx_version >= 1003003
66 : { ngx_string("If-Match"),
67 : offsetof(ngx_http_headers_in_t, if_match),
68 : ngx_http_set_builtin_header },
69 :
70 : { ngx_string("If-None-Match"),
71 : offsetof(ngx_http_headers_in_t, if_none_match),
72 : ngx_http_set_builtin_header },
73 : #endif
74 :
75 : { ngx_string("User-Agent"),
76 : offsetof(ngx_http_headers_in_t, user_agent),
77 : ngx_http_set_user_agent_header },
78 :
79 : { ngx_string("Referer"),
80 : offsetof(ngx_http_headers_in_t, referer),
81 : ngx_http_set_builtin_header },
82 :
83 : { ngx_string("Content-Length"),
84 : offsetof(ngx_http_headers_in_t, content_length),
85 : ngx_http_set_content_length_header },
86 :
87 : { ngx_string("Content-Type"),
88 : offsetof(ngx_http_headers_in_t, content_type),
89 : ngx_http_set_builtin_header },
90 :
91 : { ngx_string("Range"),
92 : offsetof(ngx_http_headers_in_t, range),
93 : ngx_http_set_builtin_header },
94 :
95 : { ngx_string("If-Range"),
96 : offsetof(ngx_http_headers_in_t, if_range),
97 : ngx_http_set_builtin_header },
98 :
99 : { ngx_string("Transfer-Encoding"),
100 : offsetof(ngx_http_headers_in_t, transfer_encoding),
101 : ngx_http_set_builtin_header },
102 :
103 : { ngx_string("Expect"),
104 : offsetof(ngx_http_headers_in_t, expect),
105 : ngx_http_set_builtin_header },
106 :
107 : #if defined(nginx_version) && nginx_version >= 1003013
108 : { ngx_string("Upgrade"),
109 : offsetof(ngx_http_headers_in_t, upgrade),
110 : ngx_http_set_builtin_header },
111 : #endif
112 :
113 : #if (NGX_HTTP_GZIP)
114 : { ngx_string("Accept-Encoding"),
115 : offsetof(ngx_http_headers_in_t, accept_encoding),
116 : ngx_http_set_builtin_header },
117 :
118 : { ngx_string("Via"),
119 : offsetof(ngx_http_headers_in_t, via),
120 : ngx_http_set_builtin_header },
121 : #endif
122 :
123 : { ngx_string("Authorization"),
124 : offsetof(ngx_http_headers_in_t, authorization),
125 : ngx_http_set_builtin_header },
126 :
127 : { ngx_string("Keep-Alive"),
128 : offsetof(ngx_http_headers_in_t, keep_alive),
129 : ngx_http_set_builtin_header },
130 :
131 : #if (NGX_HTTP_X_FORWARDED_FOR)
132 : { ngx_string("X-Forwarded-For"),
133 : offsetof(ngx_http_headers_in_t, x_forwarded_for),
134 : ngx_http_set_builtin_multi_header },
135 :
136 : #endif
137 :
138 : #if (NGX_HTTP_REALIP)
139 : { ngx_string("X-Real-IP"),
140 : offsetof(ngx_http_headers_in_t, x_real_ip),
141 : ngx_http_set_builtin_header },
142 : #endif
143 :
144 : #if (NGX_HTTP_DAV)
145 : { ngx_string("Depth"),
146 : offsetof(ngx_http_headers_in_t, depth),
147 : ngx_http_set_builtin_header },
148 :
149 : { ngx_string("Destination"),
150 : offsetof(ngx_http_headers_in_t, destination),
151 : ngx_http_set_builtin_header },
152 :
153 : { ngx_string("Overwrite"),
154 : offsetof(ngx_http_headers_in_t, overwrite),
155 : ngx_http_set_builtin_header },
156 :
157 : { ngx_string("Date"), offsetof(ngx_http_headers_in_t, date),
158 : ngx_http_set_builtin_header },
159 : #endif
160 :
161 : { ngx_string("Cookie"),
162 : offsetof(ngx_http_headers_in_t, cookies),
163 : ngx_http_set_builtin_multi_header },
164 :
165 : { ngx_null_string, 0, ngx_http_set_header }
166 : };
167 :
168 :
169 : /* request time implementation */
170 :
171 : static ngx_int_t
172 0 : ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
173 : ngx_str_t *value)
174 : {
175 0 : return ngx_http_set_header_helper(r, hv, value, NULL);
176 : }
177 :
178 :
179 : static ngx_int_t
180 0 : ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
181 : ngx_str_t *value, ngx_table_elt_t **output_header)
182 : {
183 : ngx_table_elt_t *h, *matched;
184 : ngx_list_part_t *part;
185 : ngx_uint_t i;
186 : ngx_uint_t rc;
187 :
188 0 : if (hv->no_override) {
189 0 : goto new_header;
190 : }
191 :
192 0 : matched = NULL;
193 :
194 0 : retry:
195 :
196 0 : part = &r->headers_in.headers.part;
197 0 : h = part->elts;
198 :
199 0 : for (i = 0; /* void */; i++) {
200 0 : if (i >= part->nelts) {
201 0 : if (part->next == NULL) {
202 0 : break;
203 : }
204 :
205 0 : part = part->next;
206 0 : h = part->elts;
207 0 : i = 0;
208 : }
209 :
210 : dd("i: %d, part: %p", (int) i, part);
211 :
212 0 : if (h[i].key.len == hv->key.len
213 0 : && ngx_strncasecmp(h[i].key.data, hv->key.data, h[i].key.len)
214 : == 0)
215 : {
216 0 : if (value->len == 0 || (matched && matched != &h[i])) {
217 0 : h[i].hash = 0;
218 :
219 : dd("rm header %.*s: %.*s", (int) h[i].key.len, h[i].key.data,
220 : (int) h[i].value.len, h[i].value.data);
221 :
222 0 : rc = ngx_http_lua_rm_header_helper(&r->headers_in.headers,
223 : part, i);
224 :
225 0 : ngx_http_lua_assert(!(r->headers_in.headers.part.next == NULL
226 : && r->headers_in.headers.last
227 : != &r->headers_in.headers.part));
228 :
229 : dd("rm header: rc=%d", (int) rc);
230 :
231 0 : if (rc == NGX_OK) {
232 :
233 0 : if (output_header) {
234 0 : *output_header = NULL;
235 : }
236 :
237 0 : goto retry;
238 : }
239 :
240 0 : return NGX_ERROR;
241 : }
242 :
243 0 : h[i].value = *value;
244 :
245 0 : if (output_header) {
246 0 : *output_header = &h[i];
247 : dd("setting existing builtin input header");
248 : }
249 :
250 0 : if (matched == NULL) {
251 0 : matched = &h[i];
252 : }
253 : }
254 : }
255 :
256 0 : if (matched){
257 0 : return NGX_OK;
258 : }
259 :
260 0 : if (value->len == 0) {
261 0 : return NGX_OK;
262 : }
263 :
264 0 : new_header:
265 :
266 0 : h = ngx_list_push(&r->headers_in.headers);
267 :
268 0 : if (h == NULL) {
269 0 : return NGX_ERROR;
270 : }
271 :
272 : dd("created new header for %.*s", (int) hv->key.len, hv->key.data);
273 :
274 0 : if (value->len == 0) {
275 0 : h->hash = 0;
276 :
277 : } else {
278 0 : h->hash = hv->hash;
279 : }
280 :
281 0 : h->key = hv->key;
282 0 : h->value = *value;
283 :
284 0 : h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
285 0 : if (h->lowcase_key == NULL) {
286 0 : return NGX_ERROR;
287 : }
288 :
289 0 : ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
290 :
291 0 : if (output_header) {
292 0 : *output_header = h;
293 : }
294 :
295 0 : return NGX_OK;
296 : }
297 :
298 :
299 : static ngx_int_t
300 0 : ngx_http_set_builtin_header(ngx_http_request_t *r,
301 : ngx_http_lua_header_val_t *hv, ngx_str_t *value)
302 : {
303 : ngx_table_elt_t *h, **old;
304 :
305 : dd("entered set_builtin_header (input)");
306 :
307 0 : if (hv->offset) {
308 0 : old = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset);
309 :
310 : } else {
311 0 : old = NULL;
312 : }
313 :
314 : dd("old builtin ptr ptr: %p", old);
315 : if (old) {
316 : dd("old builtin ptr: %p", *old);
317 : }
318 :
319 0 : if (old == NULL || *old == NULL) {
320 : dd("set normal header");
321 0 : return ngx_http_set_header_helper(r, hv, value, old);
322 : }
323 :
324 0 : h = *old;
325 :
326 0 : if (value->len == 0) {
327 0 : h->hash = 0;
328 0 : h->value = *value;
329 :
330 0 : return ngx_http_set_header_helper(r, hv, value, old);
331 : }
332 :
333 0 : h->hash = hv->hash;
334 0 : h->value = *value;
335 :
336 0 : return NGX_OK;
337 : }
338 :
339 :
340 : static ngx_int_t
341 0 : ngx_http_lua_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
342 : {
343 : u_char *h, ch;
344 : size_t i, dot_pos, host_len;
345 :
346 : enum {
347 : sw_usual = 0,
348 : sw_literal,
349 : sw_rest
350 : } state;
351 :
352 0 : dot_pos = host->len;
353 0 : host_len = host->len;
354 :
355 0 : h = host->data;
356 :
357 0 : state = sw_usual;
358 :
359 0 : for (i = 0; i < host->len; i++) {
360 0 : ch = h[i];
361 :
362 0 : switch (ch) {
363 :
364 0 : case '.':
365 0 : if (dot_pos == i - 1) {
366 0 : return NGX_DECLINED;
367 : }
368 0 : dot_pos = i;
369 0 : break;
370 :
371 0 : case ':':
372 0 : if (state == sw_usual) {
373 0 : host_len = i;
374 0 : state = sw_rest;
375 : }
376 0 : break;
377 :
378 0 : case '[':
379 0 : if (i == 0) {
380 0 : state = sw_literal;
381 : }
382 0 : break;
383 :
384 0 : case ']':
385 0 : if (state == sw_literal) {
386 0 : host_len = i + 1;
387 0 : state = sw_rest;
388 : }
389 0 : break;
390 :
391 0 : case '\0':
392 0 : return NGX_DECLINED;
393 :
394 0 : default:
395 :
396 0 : if (ngx_path_separator(ch)) {
397 0 : return NGX_DECLINED;
398 : }
399 :
400 0 : if (ch >= 'A' && ch <= 'Z') {
401 0 : alloc = 1;
402 : }
403 :
404 0 : break;
405 : }
406 : }
407 :
408 0 : if (dot_pos == host_len - 1) {
409 0 : host_len--;
410 : }
411 :
412 0 : if (host_len == 0) {
413 0 : return NGX_DECLINED;
414 : }
415 :
416 0 : if (alloc) {
417 0 : host->data = ngx_pnalloc(pool, host_len);
418 0 : if (host->data == NULL) {
419 0 : return NGX_ERROR;
420 : }
421 :
422 0 : ngx_strlow(host->data, h, host_len);
423 : }
424 :
425 0 : host->len = host_len;
426 :
427 0 : return NGX_OK;
428 : }
429 :
430 :
431 : static ngx_int_t
432 0 : ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
433 : ngx_str_t *value)
434 : {
435 : ngx_str_t host;
436 :
437 : dd("server new value len: %d", (int) value->len);
438 :
439 0 : if (value->len) {
440 0 : host= *value;
441 :
442 0 : if (ngx_http_lua_validate_host(&host, r->pool, 0) != NGX_OK) {
443 0 : return NGX_ERROR;
444 : }
445 :
446 0 : r->headers_in.server = host;
447 :
448 : } else {
449 0 : r->headers_in.server = *value;
450 : }
451 :
452 0 : return ngx_http_set_builtin_header(r, hv, value);
453 : }
454 :
455 :
456 : static ngx_int_t
457 0 : ngx_http_set_connection_header(ngx_http_request_t *r,
458 : ngx_http_lua_header_val_t *hv, ngx_str_t *value)
459 : {
460 0 : r->headers_in.connection_type = 0;
461 :
462 0 : if (value->len == 0) {
463 0 : return ngx_http_set_builtin_header(r, hv, value);
464 : }
465 :
466 0 : if (ngx_strcasestrn(value->data, "close", 5 - 1)) {
467 0 : r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
468 0 : r->headers_in.keep_alive_n = -1;
469 :
470 0 : } else if (ngx_strcasestrn(value->data, "keep-alive", 10 - 1)) {
471 0 : r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE;
472 : }
473 :
474 0 : return ngx_http_set_builtin_header(r, hv, value);
475 : }
476 :
477 :
478 : /* borrowed the code from ngx_http_request.c:ngx_http_process_user_agent */
479 : static ngx_int_t
480 0 : ngx_http_set_user_agent_header(ngx_http_request_t *r,
481 : ngx_http_lua_header_val_t *hv, ngx_str_t *value)
482 : {
483 : u_char *user_agent, *msie;
484 :
485 : /* clear existing settings */
486 :
487 0 : r->headers_in.msie = 0;
488 0 : r->headers_in.msie6 = 0;
489 0 : r->headers_in.opera = 0;
490 0 : r->headers_in.gecko = 0;
491 0 : r->headers_in.chrome = 0;
492 0 : r->headers_in.safari = 0;
493 0 : r->headers_in.konqueror = 0;
494 :
495 0 : if (value->len == 0) {
496 0 : return ngx_http_set_builtin_header(r, hv, value);
497 : }
498 :
499 : /* check some widespread browsers */
500 :
501 0 : user_agent = value->data;
502 :
503 0 : msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1);
504 :
505 0 : if (msie && msie + 7 < user_agent + value->len) {
506 :
507 0 : r->headers_in.msie = 1;
508 :
509 0 : if (msie[6] == '.') {
510 :
511 0 : switch (msie[5]) {
512 0 : case '4':
513 : case '5':
514 0 : r->headers_in.msie6 = 1;
515 0 : break;
516 0 : case '6':
517 0 : if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) {
518 0 : r->headers_in.msie6 = 1;
519 : }
520 0 : break;
521 : }
522 : }
523 : }
524 :
525 0 : if (ngx_strstrn(user_agent, "Opera", 5 - 1)) {
526 0 : r->headers_in.opera = 1;
527 0 : r->headers_in.msie = 0;
528 0 : r->headers_in.msie6 = 0;
529 : }
530 :
531 0 : if (!r->headers_in.msie && !r->headers_in.opera) {
532 :
533 0 : if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) {
534 0 : r->headers_in.gecko = 1;
535 :
536 0 : } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) {
537 0 : r->headers_in.chrome = 1;
538 :
539 0 : } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1)
540 0 : && ngx_strstrn(user_agent, "Mac OS X", 8 - 1))
541 : {
542 0 : r->headers_in.safari = 1;
543 :
544 0 : } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) {
545 0 : r->headers_in.konqueror = 1;
546 : }
547 : }
548 :
549 0 : return ngx_http_set_builtin_header(r, hv, value);
550 : }
551 :
552 :
553 : static ngx_int_t
554 0 : ngx_http_set_content_length_header(ngx_http_request_t *r,
555 : ngx_http_lua_header_val_t *hv, ngx_str_t *value)
556 : {
557 : off_t len;
558 :
559 0 : if (value->len == 0) {
560 0 : return ngx_http_clear_content_length_header(r, hv, value);
561 : }
562 :
563 0 : len = ngx_atosz(value->data, value->len);
564 0 : if (len == NGX_ERROR) {
565 0 : return NGX_ERROR;
566 : }
567 :
568 : dd("reset headers_in.content_length_n to %d", (int) len);
569 :
570 0 : r->headers_in.content_length_n = len;
571 :
572 0 : return ngx_http_set_builtin_header(r, hv, value);
573 : }
574 :
575 :
576 : static ngx_int_t
577 0 : ngx_http_set_builtin_multi_header(ngx_http_request_t *r,
578 : ngx_http_lua_header_val_t *hv, ngx_str_t *value)
579 : {
580 : ngx_array_t *headers;
581 : ngx_table_elt_t **v, *h;
582 :
583 0 : headers = (ngx_array_t *) ((char *) &r->headers_in + hv->offset);
584 :
585 0 : if (!hv->no_override && headers->nelts > 0) {
586 0 : ngx_array_destroy(headers);
587 :
588 0 : if (ngx_array_init(headers, r->pool, 2,
589 : sizeof(ngx_table_elt_t *))
590 : != NGX_OK)
591 : {
592 0 : return NGX_ERROR;
593 : }
594 :
595 : dd("clear multi-value headers: %d", (int) headers->nelts);
596 : }
597 :
598 : #if 1
599 0 : if (headers->nalloc == 0) {
600 0 : if (ngx_array_init(headers, r->pool, 2,
601 : sizeof(ngx_table_elt_t *))
602 : != NGX_OK)
603 : {
604 0 : return NGX_ERROR;
605 : }
606 : }
607 : #endif
608 :
609 0 : if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) {
610 0 : return NGX_ERROR;
611 : }
612 :
613 0 : if (value->len == 0) {
614 0 : return NGX_OK;
615 : }
616 :
617 : dd("new multi-value header: %p", h);
618 :
619 0 : v = ngx_array_push(headers);
620 0 : if (v == NULL) {
621 0 : return NGX_ERROR;
622 : }
623 :
624 0 : *v = h;
625 0 : return NGX_OK;
626 : }
627 :
628 :
629 : static ngx_int_t
630 0 : ngx_http_clear_content_length_header(ngx_http_request_t *r,
631 : ngx_http_lua_header_val_t *hv, ngx_str_t *value)
632 : {
633 0 : r->headers_in.content_length_n = -1;
634 :
635 0 : return ngx_http_clear_builtin_header(r, hv, value);
636 : }
637 :
638 :
639 : static ngx_int_t
640 0 : ngx_http_clear_builtin_header(ngx_http_request_t *r,
641 : ngx_http_lua_header_val_t *hv, ngx_str_t *value)
642 : {
643 0 : value->len = 0;
644 0 : return ngx_http_set_builtin_header(r, hv, value);
645 : }
646 :
647 :
648 : ngx_int_t
649 0 : ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key,
650 : ngx_str_t value, unsigned override)
651 : {
652 : ngx_http_lua_header_val_t hv;
653 0 : ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers;
654 :
655 : ngx_uint_t i;
656 :
657 : dd("set header value: %.*s", (int) value.len, value.data);
658 :
659 0 : hv.hash = ngx_hash_key_lc(key.data, key.len);
660 0 : hv.key = key;
661 :
662 0 : hv.offset = 0;
663 0 : hv.no_override = !override;
664 0 : hv.handler = NULL;
665 :
666 0 : for (i = 0; handlers[i].name.len; i++) {
667 0 : if (hv.key.len != handlers[i].name.len
668 0 : || ngx_strncasecmp(hv.key.data, handlers[i].name.data,
669 0 : handlers[i].name.len) != 0)
670 : {
671 : dd("hv key comparison: %s <> %s", handlers[i].name.data,
672 : hv.key.data);
673 :
674 0 : continue;
675 : }
676 :
677 : dd("Matched handler: %s %s", handlers[i].name.data, hv.key.data);
678 :
679 0 : hv.offset = handlers[i].offset;
680 0 : hv.handler = handlers[i].handler;
681 :
682 0 : break;
683 : }
684 :
685 0 : if (handlers[i].name.len == 0 && handlers[i].handler) {
686 0 : hv.offset = handlers[i].offset;
687 0 : hv.handler = handlers[i].handler;
688 : }
689 :
690 : #if 1
691 0 : if (hv.handler == NULL) {
692 0 : return NGX_ERROR;
693 : }
694 : #endif
695 :
696 0 : if (r->headers_out.status == 400 || r->headers_in.headers.last == NULL) {
697 : /* must be a 400 Bad Request */
698 0 : return NGX_OK;
699 : }
700 :
701 0 : return hv.handler(r, &hv, &value);
702 : }
703 :
704 :
705 : static ngx_int_t
706 0 : ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur,
707 : ngx_uint_t i)
708 : {
709 : ngx_table_elt_t *data;
710 : ngx_list_part_t *new, *part;
711 :
712 : dd("list rm item: part %p, i %d, nalloc %d", cur, (int) i,
713 : (int) l->nalloc);
714 :
715 0 : data = cur->elts;
716 :
717 : dd("cur: nelts %d, nalloc %d", (int) cur->nelts,
718 : (int) l->nalloc);
719 :
720 : dd("removing: \"%.*s:%.*s\"", (int) data[i].key.len, data[i].key.data,
721 : (int) data[i].value.len, data[i].value.data);
722 :
723 0 : if (i == 0) {
724 : dd("first entry in the part");
725 0 : cur->elts = (char *) cur->elts + l->size;
726 0 : cur->nelts--;
727 :
728 0 : if (cur == l->last) {
729 : dd("being the last part");
730 0 : if (cur->nelts == 0) {
731 : #if 1
732 0 : part = &l->part;
733 : dd("cur=%p, part=%p, part next=%p, last=%p",
734 : cur, part, part->next, l->last);
735 :
736 0 : if (part == cur) {
737 0 : cur->elts = (char *) cur->elts - l->size;
738 : /* do nothing */
739 :
740 : } else {
741 0 : while (part->next != cur) {
742 0 : if (part->next == NULL) {
743 0 : return NGX_ERROR;
744 : }
745 0 : part = part->next;
746 : }
747 :
748 0 : l->last = part;
749 0 : part->next = NULL;
750 : dd("part nelts: %d", (int) part->nelts);
751 0 : l->nalloc = part->nelts;
752 : }
753 : #endif
754 :
755 : } else {
756 0 : l->nalloc--;
757 : dd("nalloc decreased: %d", (int) l->nalloc);
758 : }
759 :
760 0 : return NGX_OK;
761 : }
762 :
763 0 : if (cur->nelts == 0) {
764 : dd("current part is empty");
765 0 : part = &l->part;
766 0 : if (part == cur) {
767 0 : ngx_http_lua_assert(cur->next != NULL);
768 :
769 : dd("remove 'cur' from the list by rewriting 'cur': "
770 : "l->last: %p, cur: %p, cur->next: %p, part: %p",
771 : l->last, cur, cur->next, part);
772 :
773 0 : if (l->last == cur->next) {
774 : dd("last is cur->next");
775 0 : l->part = *(cur->next);
776 0 : l->last = part;
777 0 : l->nalloc = part->nelts;
778 :
779 : } else {
780 0 : l->part = *(cur->next);
781 : }
782 :
783 : } else {
784 : dd("remove 'cur' from the list");
785 0 : while (part->next != cur) {
786 0 : if (part->next == NULL) {
787 0 : return NGX_ERROR;
788 : }
789 0 : part = part->next;
790 : }
791 :
792 0 : part->next = cur->next;
793 : }
794 :
795 0 : return NGX_OK;
796 : }
797 :
798 0 : return NGX_OK;
799 : }
800 :
801 0 : if (i == cur->nelts - 1) {
802 : dd("last entry in the part");
803 :
804 0 : cur->nelts--;
805 :
806 0 : if (cur == l->last) {
807 0 : l->nalloc--;
808 : }
809 :
810 0 : return NGX_OK;
811 : }
812 :
813 : dd("the middle entry in the part");
814 :
815 0 : new = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
816 0 : if (new == NULL) {
817 0 : return NGX_ERROR;
818 : }
819 :
820 0 : new->elts = &data[i + 1];
821 0 : new->nelts = cur->nelts - i - 1;
822 0 : new->next = cur->next;
823 :
824 0 : cur->nelts = i;
825 0 : cur->next = new;
826 :
827 0 : if (cur == l->last) {
828 0 : l->last = new;
829 0 : l->nalloc = new->nelts;
830 : }
831 :
832 0 : return NGX_OK;
833 : }
834 :
835 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|