bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / tomcat-connectors-1.2.32-src / native / common / jk_ajp12_worker.c
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 /***************************************************************************
19  * Description: ajpv1.2 worker, used to call local or remote jserv hosts   *
20  *              This worker is deprecated                                  *
21  * Author:      Gal Shachor <shachor@il.ibm.com>                           *
22  * Based on:    jserv_ajpv12.c from Jserv                                  *
23  * Version:     $Revision: 747878 $                                          *
24  ***************************************************************************/
25
26 #include "jk_ajp12_worker.h"
27 #include "jk_pool.h"
28 #include "jk_connect.h"
29 #include "jk_util.h"
30 #include "jk_sockbuf.h"
31 #if defined(AS400) && !defined(AS400_UTF8)
32 #include "util_ebcdic.h"
33 #include <string.h>
34 #endif
35
36 #define AJP_DEF_HOST            ("localhost")
37 #define AJP_DEF_PORT            (8007)
38 #define READ_BUF_SIZE           (8*1024)
39 #define DEF_RETRY_ATTEMPTS      (1)
40
41 struct ajp12_worker
42 {
43     struct sockaddr_in worker_inet_addr;
44     unsigned connect_retry_attempts;
45     char *name;
46     jk_worker_t worker;
47 };
48
49 typedef struct ajp12_worker ajp12_worker_t;
50
51 struct ajp12_endpoint
52 {
53     ajp12_worker_t *worker;
54
55     jk_sock_t sd;
56     jk_sockbuf_t sb;
57
58     jk_endpoint_t endpoint;
59 };
60 typedef struct ajp12_endpoint ajp12_endpoint_t;
61
62 static int ajpv12_mark(ajp12_endpoint_t * p, unsigned char type);
63
64 #if defined(AS400) && !defined(AS400_UTF8)
65 static int ajpv12_sendasciistring(ajp12_endpoint_t * p, char *buffer);
66 #endif
67
68 #if defined(AS400) && !defined(AS400_UTF8)
69 static int ajpv12_sendstring(ajp12_endpoint_t * p, char *buffer);
70 #else
71 static int ajpv12_sendstring(ajp12_endpoint_t * p, const char *buffer);
72 #endif
73
74 static int ajpv12_sendint(ajp12_endpoint_t * p, int d);
75
76 static int ajpv12_sendnbytes(ajp12_endpoint_t * p,
77                              const void *buffer, int bufferlen);
78
79 static int ajpv12_flush(ajp12_endpoint_t * p);
80
81 static int ajpv12_handle_response(ajp12_endpoint_t * p,
82                                   jk_ws_service_t *s, jk_logger_t *l);
83
84 static int ajpv12_handle_request(ajp12_endpoint_t * p,
85                                  jk_ws_service_t *s, jk_logger_t *l);
86
87 /*
88  * Return values of service() method for ajp12 worker:
89  * return value  is_error              reason
90  * JK_FALSE      JK_HTTP_SERVER_ERROR  Invalid parameters (null values)
91  *                                     Error during connect to the backend
92  *                                     ajpv12_handle_request() returns false:
93  *           Any error during reading a request body from the client or
94  *           sending the request to the backend
95  * JK_FALSE      JK_HTTP_OK            ajpv12_handle_response() returns false:
96  *           Any error during reading parts of response from backend or
97  *           sending to client
98  * JK_TRUE       JK_HTTP_OK            All other cases
99  */
100 static int JK_METHOD service(jk_endpoint_t *e,
101                              jk_ws_service_t *s,
102                              jk_logger_t *l, int *is_error)
103 {
104     ajp12_endpoint_t *p;
105     unsigned int attempt;
106     int rc = -1;
107     /*
108      * AJP12 protocol is not recoverable.
109      */
110
111     JK_TRACE_ENTER(l);
112
113     if (!e || !e->endpoint_private || !s || !is_error) {
114         JK_LOG_NULL_PARAMS(l);
115         if (is_error)
116             *is_error = JK_HTTP_SERVER_ERROR;
117         JK_TRACE_EXIT(l);
118         return JK_FALSE;
119     }
120
121     p = e->endpoint_private;
122
123     /* Set returned error to OK */
124     *is_error = JK_HTTP_OK;
125
126     for (attempt = 0; attempt < p->worker->connect_retry_attempts;
127          attempt++) {
128         p->sd =
129             jk_open_socket(&p->worker->worker_inet_addr,
130                            JK_FALSE, 0, 0, 0, l);
131
132         jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sd = %d",
133                p->sd);
134         if (IS_VALID_SOCKET(p->sd)) {
135             break;
136         }
137     }
138     if (IS_VALID_SOCKET(p->sd)) {
139
140         jk_sb_open(&p->sb, p->sd);
141         if (ajpv12_handle_request(p, s, l)) {
142             jk_log(l, JK_LOG_DEBUG,
143                    "In jk_endpoint_t::service, sent request");
144             rc = ajpv12_handle_response(p, s, l);
145             JK_TRACE_EXIT(l);
146             return rc;
147         }
148     }
149     jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, Error sd = %d",
150            p->sd);
151     *is_error = JK_HTTP_SERVER_ERROR;
152
153     JK_TRACE_EXIT(l);
154     return JK_FALSE;
155 }
156
157 static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l)
158 {
159     jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done");
160     if (e && *e && (*e)->endpoint_private) {
161         ajp12_endpoint_t *p = (*e)->endpoint_private;
162         if (IS_VALID_SOCKET(p->sd)) {
163             jk_shutdown_socket(p->sd, l);
164         }
165         free(p);
166         *e = NULL;
167         return JK_TRUE;
168     }
169
170     jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::done, NULL parameters");
171     return JK_FALSE;
172 }
173
174 static int JK_METHOD validate(jk_worker_t *pThis,
175                               jk_map_t *props,
176                               jk_worker_env_t *we, jk_logger_t *l)
177 {
178     jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate");
179
180     if (pThis && pThis->worker_private) {
181         ajp12_worker_t *p = pThis->worker_private;
182         int port = jk_get_worker_port(props,
183                                       p->name,
184                                       AJP_DEF_PORT);
185
186         const char *host = jk_get_worker_host(props,
187                                         p->name,
188                                         AJP_DEF_HOST);
189
190         jk_log(l, JK_LOG_DEBUG,
191                "In jk_worker_t::validate for worker %s contact is %s:%d",
192                p->name, host, port);
193
194         if (host) {
195             if (jk_resolve(host, port, &p->worker_inet_addr, we->pool, l)) {
196                 return JK_TRUE;
197             }
198             jk_log(l, JK_LOG_ERROR,
199                    "In jk_worker_t::validate, resolve failed");
200         }
201         jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error %s %d",
202                host, port);
203     }
204     else {
205         jk_log(l, JK_LOG_ERROR,
206                "In jk_worker_t::validate, NULL parameters");
207     }
208
209     return JK_FALSE;
210 }
211
212 static int JK_METHOD init(jk_worker_t *pThis,
213                           jk_map_t *props,
214                           jk_worker_env_t *we, jk_logger_t *log)
215 {
216     /* Nothing to do for now */
217     return JK_TRUE;
218 }
219
220 static int JK_METHOD get_endpoint(jk_worker_t *pThis,
221                                   jk_endpoint_t **pend, jk_logger_t *l)
222 {
223     jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::get_endpoint");
224
225     if (pThis && pThis->worker_private && pend) {
226         ajp12_endpoint_t *p =
227             (ajp12_endpoint_t *) malloc(sizeof(ajp12_endpoint_t));
228         if (p) {
229             p->sd = JK_INVALID_SOCKET;
230             p->worker = pThis->worker_private;
231             p->endpoint.endpoint_private = p;
232             p->endpoint.service = service;
233             p->endpoint.done = done;
234             *pend = &p->endpoint;
235             return JK_TRUE;
236         }
237         jk_log(l, JK_LOG_ERROR,
238                "In jk_worker_t::get_endpoint, malloc failed");
239     }
240     else {
241         jk_log(l, JK_LOG_ERROR,
242                "In jk_worker_t::get_endpoint, NULL parameters");
243     }
244
245     return JK_FALSE;
246 }
247
248 static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
249 {
250     jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::destroy");
251     if (pThis && *pThis && (*pThis)->worker_private) {
252         ajp12_worker_t *private_data = (*pThis)->worker_private;
253         free(private_data->name);
254         free(private_data);
255
256         return JK_TRUE;
257     }
258
259     jk_log(l, JK_LOG_ERROR, "In jk_worker_t::destroy, NULL parameters");
260     return JK_FALSE;
261 }
262
263 int JK_METHOD ajp12_worker_factory(jk_worker_t **w,
264                                    const char *name, jk_logger_t *l)
265 {
266     jk_log(l, JK_LOG_DEBUG, "Into ajp12_worker_factory");
267     if (NULL != name && NULL != w) {
268         ajp12_worker_t *private_data =
269             (ajp12_worker_t *) malloc(sizeof(ajp12_worker_t));
270
271         if (private_data) {
272             private_data->name = strdup(name);
273
274             if (private_data->name) {
275                 private_data->connect_retry_attempts = DEF_RETRY_ATTEMPTS;
276                 private_data->worker.worker_private = private_data;
277
278                 private_data->worker.validate = validate;
279                 private_data->worker.init = init;
280                 private_data->worker.get_endpoint = get_endpoint;
281                 private_data->worker.destroy = destroy;
282                 private_data->worker.maintain = NULL;
283
284                 *w = &private_data->worker;
285                 return JK_AJP12_WORKER_TYPE;
286             }
287
288             free(private_data);
289         }
290         jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, malloc failed");
291     }
292     else {
293         jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, NULL parameters");
294     }
295
296     return 0;
297 }
298
299 static int ajpv12_sendnbytes(ajp12_endpoint_t * p,
300                              const void *buffer, int bufferlen)
301 {
302     unsigned char bytes[2];
303     static const unsigned char null_b[2] =
304         { (unsigned char)0xff, (unsigned char)0xff };
305
306     if (buffer) {
307         bytes[0] = (unsigned char)((bufferlen >> 8) & 0xff);
308         bytes[1] = (unsigned char)(bufferlen & 0xff);
309
310         if (jk_sb_write(&p->sb, bytes, 2)) {
311             return jk_sb_write(&p->sb, buffer, bufferlen);
312         }
313         else {
314             return JK_FALSE;
315         }
316     }
317     else {
318         return jk_sb_write(&p->sb, null_b, 2);
319     }
320 }
321
322 #if defined(AS400) && !defined(AS400_UTF8)
323 static int ajpv12_sendasciistring(ajp12_endpoint_t * p, const char *buffer)
324 {
325     int bufferlen;
326
327     if (buffer && (bufferlen = strlen(buffer))) {
328         return ajpv12_sendnbytes(p, buffer, bufferlen);
329     }
330     else {
331         return ajpv12_sendnbytes(p, NULL, 0);
332     }
333 }
334 #endif
335
336 static int ajpv12_sendstring(ajp12_endpoint_t * p, const char *buffer)
337 {
338     int bufferlen;
339
340     if (buffer && (bufferlen = (int)strlen(buffer))) {
341 #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX)
342         char buf[2048];
343         if (bufferlen < 2048) {
344             memcpy(buf, buffer, bufferlen);
345             jk_xlate_to_ascii(buf, bufferlen);
346             return ajpv12_sendnbytes(p, buf, bufferlen);
347         }
348         else
349             return -1;
350 #else
351         return ajpv12_sendnbytes(p, buffer, bufferlen);
352 #endif
353     }
354     else {
355         return ajpv12_sendnbytes(p, NULL, 0);
356     }
357 }
358
359 static int ajpv12_mark(ajp12_endpoint_t * p, unsigned char type)
360 {
361     if (jk_sb_write(&p->sb, &type, 1)) {
362         return JK_TRUE;
363     }
364     else {
365         return JK_FALSE;
366     }
367 }
368
369 static int ajpv12_sendint(ajp12_endpoint_t * p, int d)
370 {
371     char buf[20];
372     sprintf(buf, "%d", d);
373     return ajpv12_sendstring(p, buf);
374 }
375
376 static int ajpv12_flush(ajp12_endpoint_t * p)
377 {
378     return jk_sb_flush(&p->sb);
379 }
380
381 static int ajpv12_handle_request(ajp12_endpoint_t * p,
382                                  jk_ws_service_t *s, jk_logger_t *l)
383 {
384     int ret;
385
386     jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_request");
387     /*
388      * Start the ajp 12 service sequence
389      */
390     jk_log(l, JK_LOG_DEBUG,
391            "ajpv12_handle_request, sending the ajp12 start sequence");
392
393     ret = (ajpv12_mark(p, 1) && ajpv12_sendstring(p, s->method) && ajpv12_sendstring(p, 0) &&   /* zone */
394            ajpv12_sendstring(p, 0) &&   /* servlet */
395            ajpv12_sendstring(p, s->server_name) && ajpv12_sendstring(p, 0) &&   /* doc root */
396            ajpv12_sendstring(p, 0) &&   /* path info */
397            ajpv12_sendstring(p, 0) &&   /* path translated */
398 #if defined(AS400) && !defined(AS400_UTF8)
399            ajpv12_sendasciistring(p, s->query_string) &&
400 #else
401            ajpv12_sendstring(p, s->query_string) &&
402 #endif
403            ajpv12_sendstring(p, s->remote_addr) &&
404            ajpv12_sendstring(p, s->remote_host) &&
405            ajpv12_sendstring(p, s->remote_user) &&
406            ajpv12_sendstring(p, s->auth_type) &&
407            ajpv12_sendint(p, s->server_port) &&
408 #if defined(AS400) && !defined(AS400_UTF8)
409            ajpv12_sendasciistring(p, s->method) &&
410 #else
411            ajpv12_sendstring(p, s->method) &&
412 #endif
413            ajpv12_sendstring(p, s->req_uri) && ajpv12_sendstring(p, 0) &&       /* */
414            ajpv12_sendstring(p, 0) &&   /* SCRIPT_NAME */
415 #if defined(AS400) && !defined(AS400_UTF8)
416            ajpv12_sendasciistring(p, s->server_name) &&
417 #else
418            ajpv12_sendstring(p, s->server_name) &&
419 #endif
420            ajpv12_sendint(p, s->server_port) && ajpv12_sendstring(p, s->protocol) && ajpv12_sendstring(p, 0) && /* SERVER_SIGNATURE */
421            ajpv12_sendstring(p, s->server_software) && ajpv12_sendstring(p, s->route) &&    /* JSERV_ROUTE */
422            ajpv12_sendstring(p, "") &&  /* JSERV ajpv12 compatibility */
423            ajpv12_sendstring(p, ""));   /* JSERV ajpv12 compatibility */
424
425     if (!ret) {
426         jk_log(l, JK_LOG_ERROR,
427                "In ajpv12_handle_request, failed to send the ajp12 start sequence");
428         return JK_FALSE;
429     }
430
431     if (s->num_attributes > 0) {
432         unsigned i;
433         jk_log(l, JK_LOG_DEBUG,
434                "ajpv12_handle_request, sending the environment variables");
435
436         for (i = 0; i < s->num_attributes; i++) {
437             ret = (ajpv12_mark(p, 5) &&
438                    ajpv12_sendstring(p, s->attributes_names[i]) &&
439                    ajpv12_sendstring(p, s->attributes_values[i]));
440             if (!ret) {
441                 jk_log(l, JK_LOG_ERROR,
442                        "In ajpv12_handle_request, failed to send environment");
443                 return JK_FALSE;
444             }
445         }
446     }
447
448     jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the headers");
449
450     /* Send the request headers */
451     if (s->num_headers) {
452         unsigned i;
453         for (i = 0; i < s->num_headers; ++i) {
454             ret = (ajpv12_mark(p, 3) &&
455                    ajpv12_sendstring(p, s->headers_names[i]) &&
456                    ajpv12_sendstring(p, s->headers_values[i]));
457
458             if (!ret) {
459                 jk_log(l, JK_LOG_ERROR,
460                        "In ajpv12_handle_request, failed to send headers");
461                 return JK_FALSE;
462             }
463         }
464     }
465
466     jk_log(l, JK_LOG_DEBUG,
467            "ajpv12_handle_request, sending the terminating mark");
468
469     ret = (ajpv12_mark(p, 4) && ajpv12_flush(p));
470     if (!ret) {
471         jk_log(l, JK_LOG_ERROR,
472                "In ajpv12_handle_request, failed to send the terminating mark");
473         return JK_FALSE;
474     }
475
476     if (s->content_length) {
477         char buf[READ_BUF_SIZE];
478         jk_uint64_t so_far = 0;
479
480         jk_log(l, JK_LOG_DEBUG,
481                "ajpv12_handle_request, sending the request body");
482
483         while (so_far < s->content_length) {
484             unsigned this_time = 0;
485             unsigned to_read;
486             if (s->content_length > so_far + READ_BUF_SIZE) {
487                 to_read = READ_BUF_SIZE;
488             }
489             else {
490                 to_read = (unsigned int)(s->content_length - so_far);
491             }
492
493             if (!s->read(s, buf, to_read, &this_time)) {
494                 jk_log(l, JK_LOG_ERROR,
495                        "In ajpv12_handle_request, failed to read from the web server");
496                 return JK_FALSE;
497             }
498             jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, read %d bytes",
499                    this_time);
500             if (this_time > 0) {
501                 so_far += this_time;
502                 if ((int)this_time != send(p->sd, buf, this_time, 0)) {
503                     jk_log(l, JK_LOG_ERROR,
504                            "In ajpv12_handle_request, failed to write to the container");
505                     return JK_FALSE;
506                 }
507                 jk_log(l, JK_LOG_DEBUG,
508                        "ajpv12_handle_request, sent %d bytes", this_time);
509             }
510             else if (this_time == 0) {
511                 jk_log(l, JK_LOG_ERROR,
512                        "In ajpv12_handle_request, Error: short read. content length is %" JK_UINT64_T_FMT ", read %" JK_UINT64_T_FMT,
513                        s->content_length, so_far);
514                 return JK_FALSE;
515             }
516         }
517     }
518
519     jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request done");
520     return JK_TRUE;
521 }
522
523 static int ajpv12_handle_response(ajp12_endpoint_t * p,
524                                   jk_ws_service_t *s, jk_logger_t *l)
525 {
526     int status = 200;
527     char *reason = NULL;
528     char **names = NULL;
529     char **values = NULL;
530     int headers_capacity = 0;
531     int headers_len = 0;
532     int write_to_ws;
533
534     jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_response");
535     /*
536      * Read headers ...
537      */
538     while (1) {
539         char *line = NULL;
540         char *name = NULL;
541         char *value = NULL;
542 #ifdef _MT_CODE_PTHREAD
543         char *lasts;
544 #endif
545
546         if (!jk_sb_gets(&p->sb, &line)) {
547             jk_log(l, JK_LOG_ERROR,
548                    "ajpv12_handle_response, error reading header line");
549             return JK_FALSE;
550         }
551 #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX)
552         jk_xlate_from_ascii(line, strlen(line));
553 #endif
554
555         jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s", line);
556         if (0 == strlen(line)) {
557             jk_log(l, JK_LOG_DEBUG,
558                    "ajpv12_handle_response, headers are done");
559             break;              /* Empty line -> end of headers */
560         }
561
562         name = line;
563         while (isspace((int)(*name)) && *name) {
564             name++;             /* Skip leading white chars */
565         }
566         if (!*name) {           /* Empty header name */
567             jk_log(l, JK_LOG_ERROR,
568                    "ajpv12_handle_response, empty header name");
569             return JK_FALSE;
570         }
571         if (!(value = strchr(name, ':'))) {
572             jk_log(l, JK_LOG_ERROR,
573                    "ajpv12_handle_response, no value supplied");
574             return JK_FALSE;    /* No value !!! */
575         }
576         *value = '\0';
577         value++;
578         while (isspace((int)(*value)) && *value) {
579             value++;            /* Skip leading white chars */
580         }
581         if (!*value) {          /* Empty header value */
582             jk_log(l, JK_LOG_ERROR,
583                    "ajpv12_handle_response, empty header value");
584             return JK_FALSE;
585         }
586
587         jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s=%s", name,
588                value);
589         if (0 == strcmp("Status", name)) {
590 #ifdef _MT_CODE_PTHREAD
591             char *numeric = strtok_r(value, " \t", &lasts);
592 #else
593             char *numeric = strtok(value, " \t");
594 #endif
595
596             status = atoi(numeric);
597             if (status < 100 || status > 999) {
598                 jk_log(l, JK_LOG_ERROR,
599                        "ajpv12_handle_response, invalid status code");
600                 return JK_FALSE;
601             }
602 #ifdef _MT_CODE_PTHREAD
603             reason = jk_pool_strdup(s->pool, strtok_r(NULL, " \t", &lasts));
604 #else
605             reason = jk_pool_strdup(s->pool, strtok(NULL, " \t"));
606 #endif
607         }
608         else {
609             if (headers_capacity == headers_len) {
610                 jk_log(l, JK_LOG_DEBUG,
611                        "ajpv12_handle_response, allocating header arrays");
612                 names =
613                     (char **)jk_pool_realloc(s->pool,
614                                              sizeof(char *) *
615                                              (headers_capacity + 5), names,
616                                              sizeof(char *) *
617                                              headers_capacity);
618                 values =
619                     (char **)jk_pool_realloc(s->pool,
620                                              sizeof(char *) *
621                                              (headers_capacity + 5), values,
622                                              sizeof(char *) *
623                                              headers_capacity);
624                 if (!values || !names) {
625                     jk_log(l, JK_LOG_ERROR,
626                            "ajpv12_handle_response, malloc error");
627                     return JK_FALSE;
628                 }
629                 headers_capacity = headers_capacity + 5;
630             }
631             names[headers_len] = jk_pool_strdup(s->pool, name);
632             values[headers_len] = jk_pool_strdup(s->pool, value);
633             headers_len++;
634         }
635     }
636
637     jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, starting response");
638     if (!s->start_response(s,
639                            status,
640                            reason,
641                            (const char *const *)names,
642                            (const char *const *)values, headers_len)) {
643         jk_log(l, JK_LOG_ERROR,
644                "ajpv12_handle_response, error starting response");
645         return JK_FALSE;
646     }
647
648     jk_log(l, JK_LOG_DEBUG,
649            "ajpv12_handle_response, reading response body");
650     /*
651      * Read response body
652      */
653     write_to_ws = JK_TRUE;
654     while (1) {
655         unsigned to_read = READ_BUF_SIZE;
656         unsigned acc = 0;
657         char *buf = NULL;
658
659         if (!jk_sb_read(&p->sb, &buf, to_read, &acc)) {
660             jk_log(l, JK_LOG_ERROR,
661                    "ajpv12_handle_response, error reading from ");
662             return JK_FALSE;
663         }
664
665         if (!acc) {
666             jk_log(l, JK_LOG_DEBUG,
667                    "ajpv12_handle_response, response body is done");
668             break;
669         }
670
671         if (write_to_ws) {
672             if (!s->write(s, buf, acc)) {
673                 jk_log(l, JK_LOG_ERROR,
674                        "ajpv12_handle_response, error writing back to server");
675                 write_to_ws = JK_FALSE;
676             }
677         }
678     }
679
680     jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response done");
681     return JK_TRUE;
682 }