1 #include "ngx_http_ajp.h"
2 
3 extern volatile ngx_cycle_t  *ngx_cycle;
4 
5 
6 static ngx_int_t
ajp_msg_check_header(ajp_msg_t * msg)7 ajp_msg_check_header(ajp_msg_t *msg)
8 {
9     u_char *head = msg->buf->pos;
10 
11     if (!((head[0] == 0x41 && head[1] == 0x42) ||
12           (head[0] == 0x12 && head[1] == 0x34)))
13     {
14         ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
15                       "ajp_check_msg_header() got bad signature %02Xd%02Xd",
16                       head[0], head[1]);
17 
18         return NGX_ERROR;
19     }
20 
21    return NGX_OK;
22 }
23 
24 
25 ngx_int_t
ajp_msg_is_zero_length(u_char * head)26 ajp_msg_is_zero_length(u_char *head)
27 {
28 
29     if (head[0] == 0x41 && head[1] == 0x42 &&
30         head[3] == 0x00 && head[4] == 0x00)
31     {
32         return 1;
33     }
34 
35     return 0;
36 }
37 
38 
39 ngx_int_t
ajp_msg_parse_begin(ajp_msg_t * msg)40 ajp_msg_parse_begin(ajp_msg_t *msg)
41 {
42     ngx_buf_t *buf = msg->buf;
43 
44     if (buf->last <= buf->pos + AJP_HEADER_LEN) {
45         return NGX_ERROR;
46     }
47 
48     if (ajp_msg_check_header(msg) != NGX_OK) {
49         return NGX_ERROR;
50     }
51 
52     buf->pos += AJP_HEADER_LEN;
53 
54     return NGX_OK;
55 }
56 
57 
58 ngx_int_t
ajp_msg_reset(ajp_msg_t * msg)59 ajp_msg_reset(ajp_msg_t *msg)
60 {
61     ngx_buf_t *buf = msg->buf;
62 
63     if (buf->end > buf->start + AJP_HEADER_LEN) {
64         buf->pos = buf->last = buf->start + AJP_HEADER_LEN;
65 
66     } else {
67         return NGX_ERROR;
68     }
69 
70     return NGX_OK;
71 }
72 
73 
74 ajp_msg_t *
ajp_msg_reuse(ajp_msg_t * msg)75 ajp_msg_reuse(ajp_msg_t *msg)
76 {
77     memset(msg, 0, sizeof(ajp_msg_t));
78 
79     return msg;
80 }
81 
82 
83 ngx_int_t
ajp_msg_end(ajp_msg_t * msg)84 ajp_msg_end(ajp_msg_t *msg)
85 {
86     size_t     len;
87     ngx_buf_t *buf;
88 
89     buf = msg->buf;
90     len = buf->last - buf->start - AJP_HEADER_LEN;
91 
92     if (msg->server_side) {
93         buf->start[0] = 0x41;
94         buf->start[1] = 0x42;
95     } else {
96         buf->start[0] = 0x12;
97         buf->start[1] = 0x34;
98     }
99 
100     buf->start[2] = (u_char)((len >> 8) & 0xFF);
101     buf->start[3] = (u_char)(len & 0xFF);
102 
103     buf->pos = buf->start;
104 
105     return NGX_OK;
106 }
107 
108 
109 ngx_int_t
ajp_log_overflow(ajp_msg_t * msg,const char * context)110 ajp_log_overflow(ajp_msg_t *msg, const char *context)
111 {
112     ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
113                   "%s(): BufferOverflowException pos:%p, last:%p, end:%p",
114                   context, msg->buf->pos, msg->buf->last, msg->buf->end);
115 
116     return AJP_EOVERFLOW;
117 }
118 
119 
120 ngx_int_t
ajp_msg_append_uint32(ajp_msg_t * msg,uint32_t value)121 ajp_msg_append_uint32(ajp_msg_t *msg, uint32_t value)
122 {
123     ngx_buf_t *buf;
124 
125     buf = msg->buf;
126 
127     if ((buf->last + 4) > buf->end) {
128         return ajp_log_overflow(msg, "ajp_msg_append_uint32");
129     }
130 
131     *buf->last++ = (u_char)((value >> 24) & 0xFF);
132     *buf->last++ = (u_char)((value >> 16) & 0xFF);
133     *buf->last++ = (u_char)((value >> 8) & 0xFF);
134     *buf->last++ = (u_char)(value & 0xFF);
135 
136     return NGX_OK;
137 }
138 
139 
140 ngx_int_t
ajp_msg_append_uint16(ajp_msg_t * msg,uint16_t value)141 ajp_msg_append_uint16(ajp_msg_t *msg, uint16_t value)
142 {
143     ngx_buf_t *buf;
144 
145     buf = msg->buf;
146 
147     if ((buf->last + 2) > buf->end) {
148         return ajp_log_overflow(msg, "ajp_msg_append_uint16");
149     }
150 
151     *buf->last++ = (u_char)((value >> 8) & 0xFF);
152     *buf->last++ = (u_char)(value & 0xFF);
153 
154     return NGX_OK;
155 }
156 
157 
158 ngx_int_t
ajp_msg_append_uint8(ajp_msg_t * msg,u_char value)159 ajp_msg_append_uint8(ajp_msg_t *msg, u_char value)
160 {
161     ngx_buf_t *buf;
162 
163     buf = msg->buf;
164 
165     if ((buf->last + 1) > buf->end) {
166         return ajp_log_overflow(msg, "ajp_msg_append_uint8");
167     }
168 
169     *buf->last++ = value;
170 
171     return NGX_OK;
172 }
173 
174 
175 ngx_int_t
ajp_msg_append_string(ajp_msg_t * msg,ngx_str_t * value)176 ajp_msg_append_string(ajp_msg_t *msg, ngx_str_t *value)
177 {
178     ngx_buf_t *buf;
179 
180     if (value == NULL) {
181         return(ajp_msg_append_uint16(msg, 0xFFFF));
182     }
183 
184     buf = msg->buf;
185 
186     if ((buf->last + 2 + value->len + 1) > buf->end) {
187         return ajp_log_overflow(msg, "ajp_msg_append_cvt_string");
188     }
189 
190     ajp_msg_append_uint16(msg, (uint16_t) value->len);
191 
192     ngx_memcpy(buf->last, value->data, value->len);
193     buf->last  += value->len;
194 
195     *buf->last++ = '\0';
196 
197     return NGX_OK;
198 }
199 
200 
201 ngx_int_t
ajp_msg_get_uint32(ajp_msg_t * msg,uint32_t * rvalue)202 ajp_msg_get_uint32(ajp_msg_t *msg, uint32_t *rvalue)
203 {
204     uint32_t   value;
205     ngx_buf_t *buf;
206 
207     buf = msg->buf;
208     if ((buf->pos + 4) > buf->last) {
209         return ajp_log_overflow(msg, "ajp_msg_get_uint32");
210     }
211 
212     value  = ((*buf->pos++ & 0xFF) << 24);
213     value |= ((*buf->pos++ & 0xFF) << 16);
214     value |= ((*buf->pos++ & 0xFF) << 8);
215     value |= ((*buf->pos++ & 0xFF));
216 
217     *rvalue = value;
218 
219     return NGX_OK;
220 }
221 
222 
223 ngx_int_t
ajp_msg_get_uint16(ajp_msg_t * msg,uint16_t * rvalue)224 ajp_msg_get_uint16(ajp_msg_t *msg, uint16_t *rvalue)
225 {
226     uint16_t value;
227     ngx_buf_t *buf;
228 
229     buf = msg->buf;
230 
231     if ((buf->pos + 2) > buf->last) {
232         return ajp_log_overflow(msg, "ajp_msg_get_uint16");
233     }
234 
235     value = ((*buf->pos++ & 0xFF) << 8);
236     value += ((*buf->pos++) & 0xFF);
237 
238     *rvalue = value;
239 
240     return NGX_OK;
241 }
242 
243 
244 ngx_int_t
ajp_msg_peek_uint16(ajp_msg_t * msg,uint16_t * rvalue)245 ajp_msg_peek_uint16(ajp_msg_t *msg, uint16_t *rvalue)
246 {
247     uint16_t value;
248     ngx_buf_t *buf;
249 
250     buf = msg->buf;
251 
252     if ((buf->pos + 2) > buf->last) {
253         return ajp_log_overflow(msg, "ajp_msg_peek_uint16");
254     }
255 
256     value = ((*buf->pos & 0xFF) << 8);
257     value += ((*buf->pos + 1) & 0xFF);
258 
259     *rvalue = value;
260 
261     return NGX_OK;
262 }
263 
264 
265 ngx_int_t
ajp_msg_peek_uint8(ajp_msg_t * msg,u_char * rvalue)266 ajp_msg_peek_uint8(ajp_msg_t *msg, u_char *rvalue)
267 {
268     if ((msg->buf->pos + 1) > msg->buf->last) {
269         return ajp_log_overflow(msg, "ajp_msg_peek_uint8");
270     }
271 
272     *rvalue = *msg->buf->pos;
273 
274     return NGX_OK;
275 }
276 
277 
278 ngx_int_t
ajp_msg_get_uint8(ajp_msg_t * msg,u_char * rvalue)279 ajp_msg_get_uint8(ajp_msg_t *msg, u_char *rvalue)
280 {
281     if ((msg->buf->pos + 1) > msg->buf->last) {
282         return ajp_log_overflow(msg, "ajp_msg_get_uint8");
283     }
284 
285     *rvalue = *msg->buf->pos++;
286 
287     return NGX_OK;
288 }
289 
290 
291 ngx_int_t
ajp_msg_get_string(ajp_msg_t * msg,ngx_str_t * value)292 ajp_msg_get_string(ajp_msg_t *msg, ngx_str_t *value)
293 {
294     u_char    *start;
295     uint16_t   size;
296     ngx_int_t  status;
297     ngx_buf_t *buf;
298 
299     buf = msg->buf;
300     status = ajp_msg_get_uint16(msg, &size);
301 
302     start = buf->pos;
303 
304     if ((status != NGX_OK) || (start + size + 1 > buf->last)) {
305         return ajp_log_overflow(msg, "ajp_msg_get_string");
306     }
307 
308     buf->pos += (size_t)size;
309     buf->pos++;   /* a String in AJP is NULL terminated */
310 
311     value->data = start;
312     value->len = size;
313 
314     return NGX_OK;
315 }
316 
317 
318 ngx_int_t
ajp_msg_create(ngx_pool_t * pool,size_t size,ajp_msg_t ** rmsg)319 ajp_msg_create(ngx_pool_t *pool, size_t size, ajp_msg_t **rmsg)
320 {
321     ajp_msg_t *msg;
322 
323     msg = (ajp_msg_t *)ngx_pcalloc(pool, sizeof(ajp_msg_t));
324     if (msg == NULL) {
325         return NGX_ERROR;
326     }
327 
328     msg->server_side = 0;
329 
330     msg->buf = ngx_create_temp_buf(pool, size);
331 
332     if (msg->buf == NULL) {
333         return NGX_ERROR;
334     }
335 
336     *rmsg = msg;
337 
338     return NGX_OK;
339 }
340 
341 
342 ngx_int_t
ajp_msg_create_buffer(ngx_pool_t * pool,size_t size,ajp_msg_t * msg)343 ajp_msg_create_buffer(ngx_pool_t *pool, size_t size, ajp_msg_t *msg)
344 {
345     msg->server_side = 0;
346 
347     msg->buf = ngx_create_temp_buf(pool, size);
348     if (msg->buf == NULL) {
349         return NGX_ERROR;
350     }
351 
352     return NGX_OK;
353 }
354 
355 
356 ngx_int_t
ajp_msg_create_without_buffer(ngx_pool_t * pool,ajp_msg_t ** rmsg)357 ajp_msg_create_without_buffer(ngx_pool_t *pool, ajp_msg_t **rmsg)
358 {
359     ajp_msg_t *msg;
360 
361     msg = (ajp_msg_t *)ngx_pcalloc(pool, sizeof(ajp_msg_t));
362     if (msg == NULL) {
363         return NGX_ERROR;
364     }
365 
366     msg->server_side = 0;
367 
368     *rmsg = msg;
369 
370     return NGX_OK;
371 }
372 
373 
374 ngx_int_t
ajp_alloc_data_msg(ngx_pool_t * pool,ajp_msg_t * msg)375 ajp_alloc_data_msg(ngx_pool_t *pool, ajp_msg_t *msg)
376 {
377     ngx_int_t rc;
378 
379     if ((rc = ajp_msg_create_buffer(pool, AJP_HEADER_SZ + 1, msg)) != NGX_OK) {
380         return rc;
381     }
382 
383     ajp_msg_reset(msg);
384 
385     return NGX_OK;
386 }
387 
388 
389 ngx_int_t
ajp_data_msg_end(ajp_msg_t * msg,size_t len)390 ajp_data_msg_end(ajp_msg_t *msg, size_t len)
391 {
392     ngx_buf_t *buf;
393 
394     buf = msg->buf;
395 
396     buf->last = buf->start + AJP_HEADER_SZ;
397 
398     ajp_msg_end(msg);
399 
400     buf->start[AJP_HEADER_SZ - 2] = (u_char)((len >> 8) & 0xFF);
401     buf->start[AJP_HEADER_SZ - 1] = (u_char)(len & 0xFF);
402 
403     /* len include AJP_HEADER_SIZE_LEN */
404     len += AJP_HEADER_SZ_LEN;
405     buf->start[AJP_HEADER_LEN - 2] = (u_char)((len >> 8) & 0xFF);
406     buf->start[AJP_HEADER_LEN - 1] = (u_char)(len & 0xFF);
407 
408     return NGX_OK;
409 }
410 
411 
412 u_char *
ajp_msg_dump(ngx_pool_t * pool,ajp_msg_t * msg,char * err)413 ajp_msg_dump(ngx_pool_t *pool, ajp_msg_t *msg, char *err)
414 {
415     size_t     i, len, dump;
416     u_char    *rv, *p, *last;
417     ngx_buf_t *buf;
418 
419     buf = msg->buf;
420 
421     dump = DUMP_LENGTH;
422     if (dump >(size_t)(buf->last - buf->pos)) {
423         dump = buf->last - buf->pos;
424     }
425 
426     len = dump + 256;
427     p = rv = ngx_pcalloc(pool, len);
428     if (rv == NULL) {
429         return NULL;
430     }
431 
432     last = rv + len;
433 
434     p = ngx_snprintf(p, len,
435             "ajp_msg_dump(): \"%s\", start:%p, pos:%p, last:%p \n"
436             "dump packet: \n",
437             err, buf->start, buf->pos, buf->last);
438 
439     for (i = 0; i < dump; i ++) {
440         p = ngx_snprintf(p, last - p, "%02xd ", buf->pos[i]);
441 
442         if ((i+1) % 16 == 0) {
443             p = ngx_snprintf(p, last - p, "\n");
444         }
445     }
446 
447     p = ngx_snprintf(p, last - p, "\n");
448 
449     return rv;
450 }
451 
452 
453 /* TODO: health check */
454 ngx_int_t
ajp_msg_serialize_ping(ajp_msg_t * msg)455 ajp_msg_serialize_ping(ajp_msg_t *msg)
456 {
457     ngx_int_t rc;
458 
459     ajp_msg_reset(msg);
460 
461     if ((rc = ajp_msg_append_uint8(msg, CMD_AJP13_PING)) != NGX_OK) {
462         return rc;
463     }
464 
465     return NGX_OK;
466 }
467 
468 
469 /* TODO: health check */
470 ngx_int_t
ajp_msg_serialize_cping(ajp_msg_t * msg)471 ajp_msg_serialize_cping(ajp_msg_t *msg)
472 {
473     ngx_int_t rc;
474 
475     ajp_msg_reset(msg);
476 
477     if ((rc = ajp_msg_append_uint8(msg, CMD_AJP13_CPING)) != NGX_OK) {
478         return rc;
479     }
480 
481     return NGX_OK;
482 }
483