#include "ngx_http_ajp.h" extern volatile ngx_cycle_t *ngx_cycle; static ngx_int_t ajp_msg_check_header(ajp_msg_t *msg) { u_char *head = msg->buf->pos; if (!((head[0] == 0x41 && head[1] == 0x42) || (head[0] == 0x12 && head[1] == 0x34))) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "ajp_check_msg_header() got bad signature %02Xd%02Xd", head[0], head[1]); return NGX_ERROR; } return NGX_OK; } ngx_int_t ajp_msg_is_zero_length(u_char *head) { if (head[0] == 0x41 && head[1] == 0x42 && head[3] == 0x00 && head[4] == 0x00) { return 1; } return 0; } ngx_int_t ajp_msg_parse_begin(ajp_msg_t *msg) { ngx_buf_t *buf = msg->buf; if (buf->last <= buf->pos + AJP_HEADER_LEN) { return NGX_ERROR; } if (ajp_msg_check_header(msg) != NGX_OK) { return NGX_ERROR; } buf->pos += AJP_HEADER_LEN; return NGX_OK; } ngx_int_t ajp_msg_reset(ajp_msg_t *msg) { ngx_buf_t *buf = msg->buf; if (buf->end > buf->start + AJP_HEADER_LEN) { buf->pos = buf->last = buf->start + AJP_HEADER_LEN; } else { return NGX_ERROR; } return NGX_OK; } ajp_msg_t * ajp_msg_reuse(ajp_msg_t *msg) { memset(msg, 0, sizeof(ajp_msg_t)); return msg; } ngx_int_t ajp_msg_end(ajp_msg_t *msg) { size_t len; ngx_buf_t *buf; buf = msg->buf; len = buf->last - buf->start - AJP_HEADER_LEN; if (msg->server_side) { buf->start[0] = 0x41; buf->start[1] = 0x42; } else { buf->start[0] = 0x12; buf->start[1] = 0x34; } buf->start[2] = (u_char)((len >> 8) & 0xFF); buf->start[3] = (u_char)(len & 0xFF); buf->pos = buf->start; return NGX_OK; } ngx_int_t ajp_log_overflow(ajp_msg_t *msg, const char *context) { ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0, "%s(): BufferOverflowException pos:%p, last:%p, end:%p", context, msg->buf->pos, msg->buf->last, msg->buf->end); return AJP_EOVERFLOW; } ngx_int_t ajp_msg_append_uint32(ajp_msg_t *msg, uint32_t value) { ngx_buf_t *buf; buf = msg->buf; if ((buf->last + 4) > buf->end) { return ajp_log_overflow(msg, "ajp_msg_append_uint32"); } *buf->last++ = (u_char)((value >> 24) & 0xFF); *buf->last++ = (u_char)((value >> 16) & 0xFF); *buf->last++ = (u_char)((value >> 8) & 0xFF); *buf->last++ = (u_char)(value & 0xFF); return NGX_OK; } ngx_int_t ajp_msg_append_uint16(ajp_msg_t *msg, uint16_t value) { ngx_buf_t *buf; buf = msg->buf; if ((buf->last + 2) > buf->end) { return ajp_log_overflow(msg, "ajp_msg_append_uint16"); } *buf->last++ = (u_char)((value >> 8) & 0xFF); *buf->last++ = (u_char)(value & 0xFF); return NGX_OK; } ngx_int_t ajp_msg_append_uint8(ajp_msg_t *msg, u_char value) { ngx_buf_t *buf; buf = msg->buf; if ((buf->last + 1) > buf->end) { return ajp_log_overflow(msg, "ajp_msg_append_uint8"); } *buf->last++ = value; return NGX_OK; } ngx_int_t ajp_msg_append_string(ajp_msg_t *msg, ngx_str_t *value) { ngx_buf_t *buf; if (value == NULL) { return(ajp_msg_append_uint16(msg, 0xFFFF)); } buf = msg->buf; if ((buf->last + 2 + value->len + 1) > buf->end) { return ajp_log_overflow(msg, "ajp_msg_append_cvt_string"); } ajp_msg_append_uint16(msg, (uint16_t) value->len); ngx_memcpy(buf->last, value->data, value->len); buf->last += value->len; *buf->last++ = '\0'; return NGX_OK; } ngx_int_t ajp_msg_get_uint32(ajp_msg_t *msg, uint32_t *rvalue) { uint32_t value; ngx_buf_t *buf; buf = msg->buf; if ((buf->pos + 4) > buf->last) { return ajp_log_overflow(msg, "ajp_msg_get_uint32"); } value = ((*buf->pos++ & 0xFF) << 24); value |= ((*buf->pos++ & 0xFF) << 16); value |= ((*buf->pos++ & 0xFF) << 8); value |= ((*buf->pos++ & 0xFF)); *rvalue = value; return NGX_OK; } ngx_int_t ajp_msg_get_uint16(ajp_msg_t *msg, uint16_t *rvalue) { uint16_t value; ngx_buf_t *buf; buf = msg->buf; if ((buf->pos + 2) > buf->last) { return ajp_log_overflow(msg, "ajp_msg_get_uint16"); } value = ((*buf->pos++ & 0xFF) << 8); value += ((*buf->pos++) & 0xFF); *rvalue = value; return NGX_OK; } ngx_int_t ajp_msg_peek_uint16(ajp_msg_t *msg, uint16_t *rvalue) { uint16_t value; ngx_buf_t *buf; buf = msg->buf; if ((buf->pos + 2) > buf->last) { return ajp_log_overflow(msg, "ajp_msg_peek_uint16"); } value = ((*buf->pos & 0xFF) << 8); value += ((*buf->pos + 1) & 0xFF); *rvalue = value; return NGX_OK; } ngx_int_t ajp_msg_peek_uint8(ajp_msg_t *msg, u_char *rvalue) { if ((msg->buf->pos + 1) > msg->buf->last) { return ajp_log_overflow(msg, "ajp_msg_peek_uint8"); } *rvalue = *msg->buf->pos; return NGX_OK; } ngx_int_t ajp_msg_get_uint8(ajp_msg_t *msg, u_char *rvalue) { if ((msg->buf->pos + 1) > msg->buf->last) { return ajp_log_overflow(msg, "ajp_msg_get_uint8"); } *rvalue = *msg->buf->pos++; return NGX_OK; } ngx_int_t ajp_msg_get_string(ajp_msg_t *msg, ngx_str_t *value) { u_char *start; uint16_t size; ngx_int_t status; ngx_buf_t *buf; buf = msg->buf; status = ajp_msg_get_uint16(msg, &size); start = buf->pos; if ((status != NGX_OK) || (start + size + 1 > buf->last)) { return ajp_log_overflow(msg, "ajp_msg_get_string"); } buf->pos += (size_t)size; buf->pos++; /* a String in AJP is NULL terminated */ value->data = start; value->len = size; return NGX_OK; } ngx_int_t ajp_msg_create(ngx_pool_t *pool, size_t size, ajp_msg_t **rmsg) { ajp_msg_t *msg; msg = (ajp_msg_t *)ngx_pcalloc(pool, sizeof(ajp_msg_t)); if (msg == NULL) { return NGX_ERROR; } msg->server_side = 0; msg->buf = ngx_create_temp_buf(pool, size); if (msg->buf == NULL) { return NGX_ERROR; } *rmsg = msg; return NGX_OK; } ngx_int_t ajp_msg_create_buffer(ngx_pool_t *pool, size_t size, ajp_msg_t *msg) { msg->server_side = 0; msg->buf = ngx_create_temp_buf(pool, size); if (msg->buf == NULL) { return NGX_ERROR; } return NGX_OK; } ngx_int_t ajp_msg_create_without_buffer(ngx_pool_t *pool, ajp_msg_t **rmsg) { ajp_msg_t *msg; msg = (ajp_msg_t *)ngx_pcalloc(pool, sizeof(ajp_msg_t)); if (msg == NULL) { return NGX_ERROR; } msg->server_side = 0; *rmsg = msg; return NGX_OK; } ngx_int_t ajp_alloc_data_msg(ngx_pool_t *pool, ajp_msg_t *msg) { ngx_int_t rc; if ((rc = ajp_msg_create_buffer(pool, AJP_HEADER_SZ + 1, msg)) != NGX_OK) { return rc; } ajp_msg_reset(msg); return NGX_OK; } ngx_int_t ajp_data_msg_end(ajp_msg_t *msg, size_t len) { ngx_buf_t *buf; buf = msg->buf; buf->last = buf->start + AJP_HEADER_SZ; ajp_msg_end(msg); buf->start[AJP_HEADER_SZ - 2] = (u_char)((len >> 8) & 0xFF); buf->start[AJP_HEADER_SZ - 1] = (u_char)(len & 0xFF); /* len include AJP_HEADER_SIZE_LEN */ len += AJP_HEADER_SZ_LEN; buf->start[AJP_HEADER_LEN - 2] = (u_char)((len >> 8) & 0xFF); buf->start[AJP_HEADER_LEN - 1] = (u_char)(len & 0xFF); return NGX_OK; } u_char * ajp_msg_dump(ngx_pool_t *pool, ajp_msg_t *msg, char *err) { size_t i, len, dump; u_char *rv, *p, *last; ngx_buf_t *buf; buf = msg->buf; dump = DUMP_LENGTH; if (dump >(size_t)(buf->last - buf->pos)) { dump = buf->last - buf->pos; } len = dump + 256; p = rv = ngx_pcalloc(pool, len); if (rv == NULL) { return NULL; } last = rv + len; p = ngx_snprintf(p, len, "ajp_msg_dump(): \"%s\", start:%p, pos:%p, last:%p \n" "dump packet: \n", err, buf->start, buf->pos, buf->last); for (i = 0; i < dump; i ++) { p = ngx_snprintf(p, last - p, "%02xd ", buf->pos[i]); if ((i+1) % 16 == 0) { p = ngx_snprintf(p, last - p, "\n"); } } p = ngx_snprintf(p, last - p, "\n"); return rv; } /* TODO: health check */ ngx_int_t ajp_msg_serialize_ping(ajp_msg_t *msg) { ngx_int_t rc; ajp_msg_reset(msg); if ((rc = ajp_msg_append_uint8(msg, CMD_AJP13_PING)) != NGX_OK) { return rc; } return NGX_OK; } /* TODO: health check */ ngx_int_t ajp_msg_serialize_cping(ajp_msg_t *msg) { ngx_int_t rc; ajp_msg_reset(msg); if ((rc = ajp_msg_append_uint8(msg, CMD_AJP13_CPING)) != NGX_OK) { return rc; } return NGX_OK; }