1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ajp_header.h"
18#include "ajp.h"
19
20static const char *response_trans_headers[] = {
21    "Content-Type",
22    "Content-Language",
23    "Content-Length",
24    "Date",
25    "Last-Modified",
26    "Location",
27    "Set-Cookie",
28    "Set-Cookie2",
29    "Servlet-Engine",
30    "Status",
31    "WWW-Authenticate"
32};
33
34static const char *long_res_header_for_sc(int sc)
35{
36    const char *rc = NULL;
37    sc = sc & 0X00FF;
38    if(sc <= SC_RES_HEADERS_NUM && sc > 0) {
39        rc = response_trans_headers[sc - 1];
40    }
41
42    return rc;
43}
44
45#define UNKNOWN_METHOD (-1)
46
47static int sc_for_req_header(const char *header_name)
48{
49    char header[16];
50    apr_size_t len = strlen(header_name);
51    const char *p = header_name;
52    int i = 0;
53
54    /* ACCEPT-LANGUAGE is the longest header
55     * that is of interest.
56     */
57    if (len < 4 || len > 15)
58        return UNKNOWN_METHOD;
59
60    while (*p)
61        header[i++] = apr_toupper(*p++);
62    header[i] = '\0';
63    p = &header[1];
64
65    switch (header[0]) {
66        case 'A':
67            if (memcmp(p, "CCEPT", 5) == 0) {
68                if (!header[6])
69                    return SC_ACCEPT;
70                else if (header[6] == '-') {
71                    p += 6;
72                    if (strcmp(p, "CHARSET") == 0)
73                        return SC_ACCEPT_CHARSET;
74                    else if (strcmp(p,  "ENCODING") == 0)
75                        return SC_ACCEPT_ENCODING;
76                    else if (strcmp(p, "LANGUAGE") == 0)
77                        return SC_ACCEPT_LANGUAGE;
78                    else
79                        return UNKNOWN_METHOD;
80                }
81                else
82                    return UNKNOWN_METHOD;
83            }
84            else if (strcmp(p, "UTHORIZATION") == 0)
85                return SC_AUTHORIZATION;
86            else
87                return UNKNOWN_METHOD;
88        break;
89        case 'C':
90            if(strcmp(p, "OOKIE2") == 0)
91                return SC_COOKIE2;
92            else if (strcmp(p, "OOKIE") == 0)
93                return SC_COOKIE;
94            else if(strcmp(p, "ONNECTION") == 0)
95                return SC_CONNECTION;
96            else if(strcmp(p, "ONTENT-TYPE") == 0)
97                return SC_CONTENT_TYPE;
98            else if(strcmp(p, "ONTENT-LENGTH") == 0)
99                return SC_CONTENT_LENGTH;
100            else
101                return UNKNOWN_METHOD;
102        break;
103        case 'H':
104            if(strcmp(p, "OST") == 0)
105                return SC_HOST;
106            else
107                return UNKNOWN_METHOD;
108        break;
109        case 'P':
110            if(strcmp(p, "RAGMA") == 0)
111                return SC_PRAGMA;
112            else
113                return UNKNOWN_METHOD;
114        break;
115        case 'R':
116            if(strcmp(p, "EFERER") == 0)
117                return SC_REFERER;
118            else
119                return UNKNOWN_METHOD;
120        break;
121        case 'U':
122            if(strcmp(p, "SER-AGENT") == 0)
123                return SC_USER_AGENT;
124            else
125                return UNKNOWN_METHOD;
126        break;
127        default:
128            return UNKNOWN_METHOD;
129    }
130
131    /* NOTREACHED */
132}
133
134/* Apache method number to SC methods transform table */
135static const unsigned char sc_for_req_method_table[] = {
136    SC_M_GET,
137    SC_M_PUT,
138    SC_M_POST,
139    SC_M_DELETE,
140    0,                      /* M_DELETE */
141    SC_M_OPTIONS,
142    SC_M_TRACE,
143    0,                      /* M_PATCH  */
144    SC_M_PROPFIND,
145    SC_M_PROPPATCH,
146    SC_M_MKCOL,
147    SC_M_COPY,
148    SC_M_MOVE,
149    SC_M_LOCK,
150    SC_M_UNLOCK,
151    SC_M_VERSION_CONTROL,
152    SC_M_CHECKOUT,
153    SC_M_UNCHECKOUT,
154    SC_M_CHECKIN,
155    SC_M_UPDATE,
156    SC_M_LABEL,
157    SC_M_REPORT,
158    SC_M_MKWORKSPACE,
159    SC_M_MKACTIVITY,
160    SC_M_BASELINE_CONTROL,
161    SC_M_MERGE,
162    0                       /* M_INVALID */
163};
164
165static int sc_for_req_method_by_id(request_rec *r)
166{
167    int method_id = r->method_number;
168    if (method_id < 0 || method_id > M_INVALID) {
169        return UNKNOWN_METHOD;
170    }
171    else if (r->header_only) {
172        return SC_M_HEAD;
173    }
174    else {
175        return sc_for_req_method_table[method_id] ?
176               sc_for_req_method_table[method_id] : UNKNOWN_METHOD;
177    }
178}
179
180/*
181 * Message structure
182 *
183 *
184AJPV13_REQUEST/AJPV14_REQUEST=
185    request_prefix (1) (byte)
186    method         (byte)
187    protocol       (string)
188    req_uri        (string)
189    remote_addr    (string)
190    remote_host    (string)
191    server_name    (string)
192    server_port    (short)
193    is_ssl         (boolean)
194    num_headers    (short)
195    num_headers*(req_header_name header_value)
196
197    ?context       (byte)(string)
198    ?servlet_path  (byte)(string)
199    ?remote_user   (byte)(string)
200    ?auth_type     (byte)(string)
201    ?query_string  (byte)(string)
202    ?jvm_route     (byte)(string)
203    ?ssl_cert      (byte)(string)
204    ?ssl_cipher    (byte)(string)
205    ?ssl_session   (byte)(string)
206    ?ssl_key_size  (byte)(int)      via JkOptions +ForwardKeySize
207    request_terminator (byte)
208    ?body          content_length*(var binary)
209
210 */
211
212static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg,
213                                          request_rec *r,
214                                          apr_uri_t *uri)
215{
216    int method;
217    apr_uint32_t i, num_headers = 0;
218    apr_byte_t is_ssl;
219    char *remote_host;
220    const char *session_route, *envvar;
221    const apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
222    const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts;
223
224    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
225                         "Into ajp_marshal_into_msgb");
226
227    if ((method = sc_for_req_method_by_id(r)) == UNKNOWN_METHOD) {
228        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
229               "ajp_marshal_into_msgb - Sending unknown method %s as request attribute",
230               r->method);
231        method = SC_M_JK_STORED;
232    }
233
234    is_ssl = (apr_byte_t) ap_proxy_conn_is_https(r->connection);
235
236    if (r->headers_in && apr_table_elts(r->headers_in)) {
237        const apr_array_header_t *t = apr_table_elts(r->headers_in);
238        num_headers = t->nelts;
239    }
240
241    remote_host = (char *)ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_HOST, NULL);
242
243    ajp_msg_reset(msg);
244
245    if (ajp_msg_append_uint8(msg, CMD_AJP13_FORWARD_REQUEST)     ||
246        ajp_msg_append_uint8(msg, method)                        ||
247        ajp_msg_append_string(msg, r->protocol)                  ||
248        ajp_msg_append_string(msg, uri->path)                    ||
249        ajp_msg_append_string(msg, r->connection->remote_ip)     ||
250        ajp_msg_append_string(msg, remote_host)                  ||
251        ajp_msg_append_string(msg, ap_get_server_name(r))        ||
252        ajp_msg_append_uint16(msg, (apr_uint16_t)r->connection->local_addr->port) ||
253        ajp_msg_append_uint8(msg, is_ssl)                        ||
254        ajp_msg_append_uint16(msg, (apr_uint16_t) num_headers)) {
255
256        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
257               "ajp_marshal_into_msgb: "
258               "Error appending the message begining");
259        return APR_EGENERAL;
260    }
261
262    for (i = 0 ; i < num_headers ; i++) {
263        int sc;
264        const apr_array_header_t *t = apr_table_elts(r->headers_in);
265        const apr_table_entry_t *elts = (apr_table_entry_t *)t->elts;
266
267        if ((sc = sc_for_req_header(elts[i].key)) != UNKNOWN_METHOD) {
268            if (ajp_msg_append_uint16(msg, (apr_uint16_t)sc)) {
269                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
270                       "ajp_marshal_into_msgb: "
271                       "Error appending the header name");
272                return AJP_EOVERFLOW;
273            }
274        }
275        else {
276            if (ajp_msg_append_string(msg, elts[i].key)) {
277                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
278                       "ajp_marshal_into_msgb: "
279                       "Error appending the header name");
280                return AJP_EOVERFLOW;
281            }
282        }
283
284        if (ajp_msg_append_string(msg, elts[i].val)) {
285            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
286                   "ajp_marshal_into_msgb: "
287                   "Error appending the header value");
288            return AJP_EOVERFLOW;
289        }
290        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
291                   "ajp_marshal_into_msgb: Header[%d] [%s] = [%s]",
292                   i, elts[i].key, elts[i].val);
293    }
294
295/* XXXX need to figure out how to do this
296    if (s->secret) {
297        if (ajp_msg_append_uint8(msg, SC_A_SECRET) ||
298            ajp_msg_append_string(msg, s->secret)) {
299            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
300                   "Error ajp_marshal_into_msgb - "
301                   "Error appending secret");
302            return APR_EGENERAL;
303        }
304    }
305 */
306
307    if (r->user) {
308        if (ajp_msg_append_uint8(msg, SC_A_REMOTE_USER) ||
309            ajp_msg_append_string(msg, r->user)) {
310            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
311                   "ajp_marshal_into_msgb: "
312                   "Error appending the remote user");
313            return AJP_EOVERFLOW;
314        }
315    }
316    if (r->ap_auth_type) {
317        if (ajp_msg_append_uint8(msg, SC_A_AUTH_TYPE) ||
318            ajp_msg_append_string(msg, r->ap_auth_type)) {
319            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
320                   "ajp_marshal_into_msgb: "
321                   "Error appending the auth type");
322            return AJP_EOVERFLOW;
323        }
324    }
325    /* XXXX  ebcdic (args converted?) */
326    if (uri->query) {
327        if (ajp_msg_append_uint8(msg, SC_A_QUERY_STRING) ||
328            ajp_msg_append_string(msg, uri->query)) {
329            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
330                   "ajp_marshal_into_msgb: "
331                   "Error appending the query string");
332            return AJP_EOVERFLOW;
333        }
334    }
335    if ((session_route = apr_table_get(r->notes, "session-route"))) {
336        if (ajp_msg_append_uint8(msg, SC_A_JVM_ROUTE) ||
337            ajp_msg_append_string(msg, session_route)) {
338            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
339                   "ajp_marshal_into_msgb: "
340                   "Error appending the jvm route");
341            return AJP_EOVERFLOW;
342        }
343    }
344/* XXX: Is the subprocess_env a right place?
345 * <Location /examples>
346 *   ProxyPass ajp://remote:8009/servlets-examples
347 *   SetEnv SSL_SESSION_ID CUSTOM_SSL_SESSION_ID
348 * </Location>
349 */
350    /*
351     * Only lookup SSL variables if we are currently running HTTPS.
352     * Furthermore ensure that only variables get set in the AJP message
353     * that are not NULL and not empty.
354     */
355    if (is_ssl) {
356        if ((envvar = ap_proxy_ssl_val(r->pool, r->server, r->connection, r,
357                                       AJP13_SSL_CLIENT_CERT_INDICATOR))
358            && envvar[0]) {
359            if (ajp_msg_append_uint8(msg, SC_A_SSL_CERT)
360                || ajp_msg_append_string(msg, envvar)) {
361                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
362                             "ajp_marshal_into_msgb: "
363                             "Error appending the SSL certificates");
364                return AJP_EOVERFLOW;
365            }
366        }
367
368        if ((envvar = ap_proxy_ssl_val(r->pool, r->server, r->connection, r,
369                                       AJP13_SSL_CIPHER_INDICATOR))
370            && envvar[0]) {
371            if (ajp_msg_append_uint8(msg, SC_A_SSL_CIPHER)
372                || ajp_msg_append_string(msg, envvar)) {
373                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
374                             "ajp_marshal_into_msgb: "
375                             "Error appending the SSL ciphers");
376                return AJP_EOVERFLOW;
377            }
378        }
379
380        if ((envvar = ap_proxy_ssl_val(r->pool, r->server, r->connection, r,
381                                       AJP13_SSL_SESSION_INDICATOR))
382            && envvar[0]) {
383            if (ajp_msg_append_uint8(msg, SC_A_SSL_SESSION)
384                || ajp_msg_append_string(msg, envvar)) {
385                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
386                             "ajp_marshal_into_msgb: "
387                             "Error appending the SSL session");
388                return AJP_EOVERFLOW;
389            }
390        }
391
392        /* ssl_key_size is required by Servlet 2.3 API */
393        if ((envvar = ap_proxy_ssl_val(r->pool, r->server, r->connection, r,
394                                       AJP13_SSL_KEY_SIZE_INDICATOR))
395            && envvar[0]) {
396
397            if (ajp_msg_append_uint8(msg, SC_A_SSL_KEY_SIZE)
398                || ajp_msg_append_uint16(msg, (unsigned short) atoi(envvar))) {
399                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
400                             "Error ajp_marshal_into_msgb - "
401                             "Error appending the SSL key size");
402                return APR_EGENERAL;
403            }
404        }
405    }
406    /* If the method was unrecognized, encode it as an attribute */
407    if (method == SC_M_JK_STORED) {
408        if (ajp_msg_append_uint8(msg, SC_A_STORED_METHOD)
409            || ajp_msg_append_string(msg, r->method)) {
410            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
411                         "ajp_marshal_into_msgb: "
412                         "Error appending the method '%s' as request attribute",
413                         r->method);
414            return AJP_EOVERFLOW;
415        }
416    }
417    /* Forward the remote port information, which was forgotten
418     * from the builtin data of the AJP 13 protocol.
419     * Since the servlet spec allows to retrieve it via getRemotePort(),
420     * we provide the port to the Tomcat connector as a request
421     * attribute. Modern Tomcat versions know how to retrieve
422     * the remote port from this attribute.
423     */
424    {
425        const char *key = SC_A_REQ_REMOTE_PORT;
426        char *val = apr_itoa(r->pool, r->connection->remote_addr->port);
427        if (ajp_msg_append_uint8(msg, SC_A_REQ_ATTRIBUTE) ||
428            ajp_msg_append_string(msg, key)   ||
429            ajp_msg_append_string(msg, val)) {
430            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
431                    "ajp_marshal_into_msgb: "
432                    "Error appending attribute %s=%s",
433                    key, val);
434            return AJP_EOVERFLOW;
435        }
436    }
437    /* Use the environment vars prefixed with AJP_
438     * and pass it to the header striping that prefix.
439     */
440    for (i = 0; i < (apr_uint32_t)arr->nelts; i++) {
441        if (!strncmp(elts[i].key, "AJP_", 4)) {
442            if (ajp_msg_append_uint8(msg, SC_A_REQ_ATTRIBUTE) ||
443                ajp_msg_append_string(msg, elts[i].key + 4)   ||
444                ajp_msg_append_string(msg, elts[i].val)) {
445                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
446                        "ajp_marshal_into_msgb: "
447                        "Error appending attribute %s=%s",
448                        elts[i].key, elts[i].val);
449                return AJP_EOVERFLOW;
450            }
451        }
452    }
453
454    if (ajp_msg_append_uint8(msg, SC_A_ARE_DONE)) {
455        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
456               "ajp_marshal_into_msgb: "
457               "Error appending the message end");
458        return AJP_EOVERFLOW;
459    }
460
461    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
462            "ajp_marshal_into_msgb: Done");
463    return APR_SUCCESS;
464}
465
466/*
467AJPV13_RESPONSE/AJPV14_RESPONSE:=
468    response_prefix (2)
469    status          (short)
470    status_msg      (short)
471    num_headers     (short)
472    num_headers*(res_header_name header_value)
473    *body_chunk
474    terminator      boolean <! -- recycle connection or not  -->
475
476req_header_name :=
477    sc_req_header_name | (string)
478
479res_header_name :=
480    sc_res_header_name | (string)
481
482header_value :=
483    (string)
484
485body_chunk :=
486    length  (short)
487    body    length*(var binary)
488
489 */
490
491static int addit_dammit(void *v, const char *key, const char *val)
492{
493    apr_table_addn(v, key, val);
494    return 1;
495}
496
497static apr_status_t ajp_unmarshal_response(ajp_msg_t *msg,
498                                           request_rec *r,
499                                           proxy_dir_conf *dconf)
500{
501    apr_uint16_t status;
502    apr_status_t rc;
503    const char *ptr;
504    apr_uint16_t  num_headers;
505    int i;
506
507    rc = ajp_msg_get_uint16(msg, &status);
508
509    if (rc != APR_SUCCESS) {
510         ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
511                "ajp_unmarshal_response: Null status");
512        return rc;
513    }
514    r->status = status;
515
516    rc = ajp_msg_get_string(msg, &ptr);
517    if (rc == APR_SUCCESS) {
518#if defined(AS400) || defined(_OSD_POSIX) /* EBCDIC platforms */
519        ptr = apr_pstrdup(r->pool, ptr);
520        ap_xlate_proto_from_ascii(ptr, strlen(ptr));
521#endif
522        r->status_line =  apr_psprintf(r->pool, "%d %s", status, ptr);
523    } else {
524        r->status_line = NULL;
525    }
526
527    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
528           "ajp_unmarshal_response: status = %d", status);
529
530    rc = ajp_msg_get_uint16(msg, &num_headers);
531    if (rc == APR_SUCCESS) {
532        apr_table_t *save_table;
533
534        /* First, tuck away all already existing cookies */
535        /*
536         * Could optimize here, but just in case we want to
537         * also save other headers, keep this logic.
538         */
539        save_table = apr_table_make(r->pool, num_headers + 2);
540        apr_table_do(addit_dammit, save_table, r->headers_out,
541                     "Set-Cookie", NULL);
542        r->headers_out = save_table;
543    } else {
544        r->headers_out = NULL;
545        num_headers = 0;
546    }
547
548    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
549           "ajp_unmarshal_response: Number of headers is = %d",
550           num_headers);
551
552    for(i = 0 ; i < (int) num_headers ; i++) {
553        apr_uint16_t name;
554        const char *stringname;
555        const char *value;
556        rc  = ajp_msg_peek_uint16(msg, &name);
557        if (rc != APR_SUCCESS) {
558            return rc;
559        }
560
561        if ((name & 0XFF00) == 0XA000) {
562            ajp_msg_get_uint16(msg, &name);
563            stringname = long_res_header_for_sc(name);
564            if (stringname == NULL) {
565                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
566                       "ajp_unmarshal_response: "
567                       "No such sc (%08x)",
568                       name);
569                return AJP_EBAD_HEADER;
570            }
571        } else {
572            name = 0;
573            rc = ajp_msg_get_string(msg, &stringname);
574            if (rc != APR_SUCCESS) {
575                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
576                       "ajp_unmarshal_response: "
577                       "Null header name");
578                return rc;
579            }
580#if defined(AS400) || defined(_OSD_POSIX)
581            ap_xlate_proto_from_ascii(stringname, strlen(stringname));
582#endif
583        }
584
585        rc = ajp_msg_get_string(msg, &value);
586        if (rc != APR_SUCCESS) {
587            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
588                   "ajp_unmarshal_response: "
589                   "Null header value");
590            return rc;
591        }
592
593        /* Set-Cookie need additional processing */
594        if (!strcasecmp(stringname, "Set-Cookie")) {
595            value = ap_proxy_cookie_reverse_map(r, dconf, value);
596        }
597        /* Location, Content-Location, URI and Destination need additional
598         * processing */
599        else if (!strcasecmp(stringname, "Location")
600                 || !strcasecmp(stringname, "Content-Location")
601                 || !strcasecmp(stringname, "URI")
602                 || !strcasecmp(stringname, "Destination"))
603        {
604          value = ap_proxy_location_reverse_map(r, dconf, value);
605        }
606
607#if defined(AS400) || defined(_OSD_POSIX)
608        ap_xlate_proto_from_ascii(value, strlen(value));
609#endif
610        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
611               "ajp_unmarshal_response: Header[%d] [%s] = [%s]",
612                       i, stringname, value);
613
614        apr_table_add(r->headers_out, stringname, value);
615
616        /* Content-type needs an additional handling */
617        if (strcasecmp(stringname, "Content-Type") == 0) {
618             /* add corresponding filter */
619            ap_set_content_type(r, apr_pstrdup(r->pool, value));
620            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
621               "ajp_unmarshal_response: ap_set_content_type done");
622        }
623    }
624
625    return APR_SUCCESS;
626}
627
628/*
629 * Build the ajp header message and send it
630 */
631apr_status_t ajp_send_header(apr_socket_t *sock,
632                             request_rec *r,
633                             apr_size_t buffsize,
634                             apr_uri_t *uri)
635{
636    ajp_msg_t *msg;
637    apr_status_t rc;
638
639    rc = ajp_msg_create(r->pool, buffsize, &msg);
640    if (rc != APR_SUCCESS) {
641        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
642               "ajp_send_header: ajp_msg_create failed");
643        return rc;
644    }
645
646    rc = ajp_marshal_into_msgb(msg, r, uri);
647    if (rc != APR_SUCCESS) {
648        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
649               "ajp_send_header: ajp_marshal_into_msgb failed");
650        return rc;
651    }
652
653    rc = ajp_ilink_send(sock, msg);
654    if (rc != APR_SUCCESS) {
655        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
656               "ajp_send_header: ajp_ilink_send failed");
657        return rc;
658    }
659
660    return APR_SUCCESS;
661}
662
663/*
664 * Read the ajp message and return the type of the message.
665 */
666apr_status_t ajp_read_header(apr_socket_t *sock,
667                             request_rec  *r,
668                             apr_size_t buffsize,
669                             ajp_msg_t **msg)
670{
671    apr_byte_t result;
672    apr_status_t rc;
673
674    if (*msg) {
675        rc = ajp_msg_reuse(*msg);
676        if (rc != APR_SUCCESS) {
677            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
678                   "ajp_read_header: ajp_msg_reuse failed");
679            return rc;
680        }
681    }
682    else {
683        rc = ajp_msg_create(r->pool, buffsize, msg);
684        if (rc != APR_SUCCESS) {
685            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
686                   "ajp_read_header: ajp_msg_create failed");
687            return rc;
688        }
689    }
690    ajp_msg_reset(*msg);
691    rc = ajp_ilink_receive(sock, *msg);
692    if (rc != APR_SUCCESS) {
693        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
694               "ajp_read_header: ajp_ilink_receive failed");
695        return rc;
696    }
697    rc = ajp_msg_peek_uint8(*msg, &result);
698    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
699               "ajp_read_header: ajp_ilink_received %02x", result);
700    return APR_SUCCESS;
701}
702
703/* parse the msg to read the type */
704int ajp_parse_type(request_rec  *r, ajp_msg_t *msg)
705{
706    apr_byte_t result;
707    ajp_msg_peek_uint8(msg, &result);
708    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
709               "ajp_parse_type: got %02x", result);
710    return (int) result;
711}
712
713/* parse the header */
714apr_status_t ajp_parse_header(request_rec  *r, proxy_dir_conf *conf,
715                              ajp_msg_t *msg)
716{
717    apr_byte_t result;
718    apr_status_t rc;
719
720    rc = ajp_msg_get_uint8(msg, &result);
721    if (rc != APR_SUCCESS) {
722        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
723               "ajp_parse_headers: ajp_msg_get_byte failed");
724        return rc;
725    }
726    if (result != CMD_AJP13_SEND_HEADERS) {
727        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
728               "ajp_parse_headers: wrong type 0x%02x expecting 0x%02x",
729               result, CMD_AJP13_SEND_HEADERS);
730        return AJP_EBAD_HEADER;
731    }
732    return ajp_unmarshal_response(msg, r, conf);
733}
734
735/* parse the body and return data address and length */
736apr_status_t  ajp_parse_data(request_rec  *r, ajp_msg_t *msg,
737                             apr_uint16_t *len, char **ptr)
738{
739    apr_byte_t result;
740    apr_status_t rc;
741    apr_uint16_t expected_len;
742
743    rc = ajp_msg_get_uint8(msg, &result);
744    if (rc != APR_SUCCESS) {
745        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
746               "ajp_parse_data: ajp_msg_get_byte failed");
747        return rc;
748    }
749    if (result != CMD_AJP13_SEND_BODY_CHUNK) {
750        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
751               "ajp_parse_data: wrong type 0x%02x expecting 0x%02x",
752               result, CMD_AJP13_SEND_BODY_CHUNK);
753        return AJP_EBAD_HEADER;
754    }
755    rc = ajp_msg_get_uint16(msg, len);
756    if (rc != APR_SUCCESS) {
757        return rc;
758    }
759    /*
760     * msg->len contains the complete length of the message including all
761     * headers. So the expected length for a CMD_AJP13_SEND_BODY_CHUNK is
762     * msg->len minus the sum of
763     * AJP_HEADER_LEN    : The length of the header to every AJP message.
764     * AJP_HEADER_SZ_LEN : The header giving the size of the chunk.
765     * 1                 : The CMD_AJP13_SEND_BODY_CHUNK indicator byte (0x03).
766     * 1                 : The last byte of this message always seems to be
767     *                     0x00 and is not part of the chunk.
768     */
769    expected_len = msg->len - (AJP_HEADER_LEN + AJP_HEADER_SZ_LEN + 1 + 1);
770    if (*len != expected_len) {
771        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
772               "ajp_parse_data: Wrong chunk length. Length of chunk is %i,"
773               " expected length is %i.", *len, expected_len);
774        return AJP_EBAD_HEADER;
775    }
776    *ptr = (char *)&(msg->buf[msg->pos]);
777    return APR_SUCCESS;
778}
779
780/* Check the reuse flag in CMD_AJP13_END_RESPONSE */
781apr_status_t ajp_parse_reuse(request_rec *r, ajp_msg_t *msg,
782                             apr_byte_t *reuse)
783{
784    apr_byte_t result;
785    apr_status_t rc;
786
787    rc = ajp_msg_get_uint8(msg, &result);
788    if (rc != APR_SUCCESS) {
789        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
790               "ajp_parse_reuse: ajp_msg_get_byte failed");
791        return rc;
792    }
793    if (result != CMD_AJP13_END_RESPONSE) {
794        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
795               "ajp_parse_reuse: wrong type 0x%02x expecting 0x%02x",
796               result, CMD_AJP13_END_RESPONSE);
797        return AJP_EBAD_HEADER;
798    }
799    return ajp_msg_get_uint8(msg, reuse);
800}
801
802/*
803 * Allocate a msg to send data
804 */
805apr_status_t  ajp_alloc_data_msg(apr_pool_t *pool, char **ptr, apr_size_t *len,
806                                 ajp_msg_t **msg)
807{
808    apr_status_t rc;
809
810    if ((rc = ajp_msg_create(pool, *len, msg)) != APR_SUCCESS)
811        return rc;
812    ajp_msg_reset(*msg);
813    *ptr = (char *)&((*msg)->buf[6]);
814    *len =  *len - 6;
815
816    return APR_SUCCESS;
817}
818
819/*
820 * Send the data message
821 */
822apr_status_t  ajp_send_data_msg(apr_socket_t *sock,
823                                ajp_msg_t *msg, apr_size_t len)
824{
825
826    msg->buf[4] = (apr_byte_t)((len >> 8) & 0xFF);
827    msg->buf[5] = (apr_byte_t)(len & 0xFF);
828
829    msg->len += len + 2; /* + 1 XXXX where is '\0' */
830
831    return ajp_ilink_send(sock, msg);
832
833}
834