nxt_http_chunk_parse.c (704:1fcac04f0a15) nxt_http_chunk_parse.c (1505:d18f2b38596b)
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8

--- 7 unchanged lines hidden (view full) ---

16nxt_size_is_sufficient(cs) \
17 (cs < ((__typeof__(cs)) 1 << (sizeof(cs) * 8 - 4)))
18
19
20static nxt_int_t nxt_http_chunk_buffer(nxt_http_chunk_parse_t *hcp,
21 nxt_buf_t ***tail, nxt_buf_t *in);
22
23
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8

--- 7 unchanged lines hidden (view full) ---

16nxt_size_is_sufficient(cs) \
17 (cs < ((__typeof__(cs)) 1 << (sizeof(cs) * 8 - 4)))
18
19
20static nxt_int_t nxt_http_chunk_buffer(nxt_http_chunk_parse_t *hcp,
21 nxt_buf_t ***tail, nxt_buf_t *in);
22
23
24static void nxt_http_chunk_buf_completion(nxt_task_t *task, void *obj,
25 void *data);
26
27
24nxt_buf_t *
25nxt_http_chunk_parse(nxt_task_t *task, nxt_http_chunk_parse_t *hcp,
26 nxt_buf_t *in)
27{
28 u_char c, ch;
29 nxt_int_t ret;
28nxt_buf_t *
29nxt_http_chunk_parse(nxt_task_t *task, nxt_http_chunk_parse_t *hcp,
30 nxt_buf_t *in)
31{
32 u_char c, ch;
33 nxt_int_t ret;
30 nxt_buf_t *b, *out, *nb, **tail;
34 nxt_buf_t *b, *out, *next, **tail;
31 enum {
32 sw_start = 0,
33 sw_chunk_size,
34 sw_chunk_size_linefeed,
35 sw_chunk_end_newline,
36 sw_chunk_end_linefeed,
37 sw_chunk,
38 } state;
39
35 enum {
36 sw_start = 0,
37 sw_chunk_size,
38 sw_chunk_size_linefeed,
39 sw_chunk_end_newline,
40 sw_chunk_end_linefeed,
41 sw_chunk,
42 } state;
43
44 next = NULL;
40 out = NULL;
41 tail = &out;
42
43 state = hcp->state;
44
45 out = NULL;
46 tail = &out;
47
48 state = hcp->state;
49
45 for (b = in; b != NULL; b = b->next) {
50 for (b = in; b != NULL; b = next) {
46
47 hcp->pos = b->mem.pos;
48
49 while (hcp->pos < b->mem.free) {
50 /*
51 * The sw_chunk state is tested outside the switch
52 * to preserve hcp->pos and to not touch memory.
53 */
54 if (state == sw_chunk) {
55 ret = nxt_http_chunk_buffer(hcp, &tail, b);
56
57 if (ret == NXT_HTTP_CHUNK_MIDDLE) {
58 goto next;
59 }
60
61 if (nxt_slow_path(ret == NXT_ERROR)) {
62 hcp->error = 1;
51
52 hcp->pos = b->mem.pos;
53
54 while (hcp->pos < b->mem.free) {
55 /*
56 * The sw_chunk state is tested outside the switch
57 * to preserve hcp->pos and to not touch memory.
58 */
59 if (state == sw_chunk) {
60 ret = nxt_http_chunk_buffer(hcp, &tail, b);
61
62 if (ret == NXT_HTTP_CHUNK_MIDDLE) {
63 goto next;
64 }
65
66 if (nxt_slow_path(ret == NXT_ERROR)) {
67 hcp->error = 1;
63 goto done;
68 return out;
64 }
65
66 state = sw_chunk_end_newline;
67
68 if (ret == NXT_HTTP_CHUNK_END_ON_BORDER) {
69 goto next;
70 }
71

--- 75 unchanged lines hidden (view full) ---

147 case sw_chunk_end_linefeed:
148 if (nxt_fast_path(ch == '\n')) {
149
150 if (!hcp->last) {
151 state = sw_start;
152 continue;
153 }
154
69 }
70
71 state = sw_chunk_end_newline;
72
73 if (ret == NXT_HTTP_CHUNK_END_ON_BORDER) {
74 goto next;
75 }
76

--- 75 unchanged lines hidden (view full) ---

152 case sw_chunk_end_linefeed:
153 if (nxt_fast_path(ch == '\n')) {
154
155 if (!hcp->last) {
156 state = sw_start;
157 continue;
158 }
159
155 goto done;
160 return out;
156 }
157
158 goto chunk_error;
159
160 case sw_chunk:
161 /*
162 * This state is processed before the switch.
163 * It added here just to suppress a warning.
164 */
165 continue;
166 }
167 }
168
169 if (b->retain == 0) {
170 /* No chunk data was found in a buffer. */
161 }
162
163 goto chunk_error;
164
165 case sw_chunk:
166 /*
167 * This state is processed before the switch.
168 * It added here just to suppress a warning.
169 */
170 continue;
171 }
172 }
173
174 if (b->retain == 0) {
175 /* No chunk data was found in a buffer. */
171 nxt_thread_current_work_queue_add(task->thread,
172 b->completion_handler,
173 task, b, b->parent);
176 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
177 b->completion_handler, task, b, b->parent);
174
175 }
176
177 next:
178
178
179 }
180
181 next:
182
179 continue;
183 next = b->next;
184 b->next = NULL;
180 }
181
182 hcp->state = state;
183
184 return out;
185
186chunk_error:
187
188 hcp->chunk_error = 1;
189
185 }
186
187 hcp->state = state;
188
189 return out;
190
191chunk_error:
192
193 hcp->chunk_error = 1;
194
190done:
191
192 nb = nxt_buf_sync_alloc(hcp->mem_pool, NXT_BUF_SYNC_LAST);
193
194 if (nxt_fast_path(nb != NULL)) {
195 *tail = nb;
196
197 } else {
198 hcp->error = 1;
199 }
200
201 // STUB: hcp->chunk_error = 1;
202 // STUB: hcp->error = 1;
203
204 return out;
205}
206
207
208static nxt_int_t
209nxt_http_chunk_buffer(nxt_http_chunk_parse_t *hcp, nxt_buf_t ***tail,
210 nxt_buf_t *in)
211{
212 u_char *p;
213 size_t size;
214 nxt_buf_t *b;
215
216 p = hcp->pos;
217 size = in->mem.free - p;
218
195 return out;
196}
197
198
199static nxt_int_t
200nxt_http_chunk_buffer(nxt_http_chunk_parse_t *hcp, nxt_buf_t ***tail,
201 nxt_buf_t *in)
202{
203 u_char *p;
204 size_t size;
205 nxt_buf_t *b;
206
207 p = hcp->pos;
208 size = in->mem.free - p;
209
219 if (hcp->chunk_size >= size && in->retain == 0) {
220 /*
221 * Use original buffer if the buffer is lesser than or equal
222 * to a chunk size and this is the first chunk in the buffer.
223 */
224 in->mem.pos = p;
225 **tail = in;
226 *tail = &in->next;
210 b = nxt_buf_mem_alloc(hcp->mem_pool, 0, 0);
211 if (nxt_slow_path(b == NULL)) {
212 return NXT_ERROR;
213 }
227
214
228 } else {
229 b = nxt_buf_mem_alloc(hcp->mem_pool, 0, 0);
230 if (nxt_slow_path(b == NULL)) {
231 return NXT_ERROR;
232 }
215 **tail = b;
216 *tail = &b->next;
233
217
234 **tail = b;
235 *tail = &b->next;
218 nxt_mp_retain(hcp->mem_pool);
219 b->completion_handler = nxt_http_chunk_buf_completion;
236
220
237 b->parent = in;
238 in->retain++;
239 b->mem.pos = p;
240 b->mem.start = p;
221 b->parent = in;
222 in->retain++;
223 b->mem.pos = p;
224 b->mem.start = p;
241
225
242 if (hcp->chunk_size < size) {
243 p += hcp->chunk_size;
244 hcp->pos = p;
226 if (hcp->chunk_size < size) {
227 p += hcp->chunk_size;
228 hcp->pos = p;
245
229
246 b->mem.free = p;
247 b->mem.end = p;
230 b->mem.free = p;
231 b->mem.end = p;
248
232
249 return NXT_HTTP_CHUNK_END;
250 }
251
252 b->mem.free = in->mem.free;
253 b->mem.end = in->mem.free;
233 return NXT_HTTP_CHUNK_END;
254 }
255
234 }
235
236 b->mem.free = in->mem.free;
237 b->mem.end = in->mem.free;
238
256 hcp->chunk_size -= size;
257
258 if (hcp->chunk_size == 0) {
259 return NXT_HTTP_CHUNK_END_ON_BORDER;
260 }
261
262 return NXT_HTTP_CHUNK_MIDDLE;
263}
239 hcp->chunk_size -= size;
240
241 if (hcp->chunk_size == 0) {
242 return NXT_HTTP_CHUNK_END_ON_BORDER;
243 }
244
245 return NXT_HTTP_CHUNK_MIDDLE;
246}
247
248
249static void
250nxt_http_chunk_buf_completion(nxt_task_t *task, void *obj, void *data)
251{
252 nxt_mp_t *mp;
253 nxt_buf_t *b, *next, *parent;
254
255 b = obj;
256 parent = data;
257
258 nxt_debug(task, "buf completion: %p %p", b, b->mem.start);
259
260 nxt_assert(data == b->parent);
261
262 do {
263 next = b->next;
264 parent = b->parent;
265 mp = b->data;
266
267 nxt_mp_free(mp, b);
268 nxt_mp_release(mp);
269
270 nxt_buf_parent_completion(task, parent);
271
272 b = next;
273 } while (b != NULL);
274}