OSDN Git Service

* Fixed Bug.
[modchxj/mod_chxj.git] / src / chxj_serf.c
1 /*
2  * Copyright (C) 2005-2009 Atsushi Konno All rights reserved.
3  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * 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 #include "chxj_serf.h"
18 #include "mod_chxj.h"
19 #include "apr_pools.h"
20
21 typedef struct __app_ctx_t     app_ctx_t;
22 typedef struct __handler_ctx_t handler_ctx_t;
23
24 struct __app_ctx_t {
25   int                 ssl_flag;
26   serf_ssl_context_t  *ssl_ctx;
27   serf_bucket_alloc_t *bkt_alloc;
28 };
29
30 struct __handler_ctx_t {
31 #if APR_MAJOR_VERSION > 0
32   apr_uint32_t requests_outstanding;
33 #else
34   apr_atomic_t requests_outstanding;
35 #endif
36
37   serf_response_acceptor_t acceptor;
38   app_ctx_t                *acceptor_ctx;
39
40   serf_response_handler_t  handler;
41
42   const char *host;
43   const char *method;
44   const char *path;
45   const char *user_agent;
46
47   apr_status_t rv;
48   const char *reason;
49   int response_code;
50
51   char *response;
52   apr_size_t response_len;
53   char *post_data;
54   apr_size_t post_data_len;
55   apr_table_t *headers_out;
56   apr_pool_t *pool;
57   request_rec *r;
58 };
59
60 char *default_chxj_serf_get(request_rec *r, apr_pool_t *ppool, const char *url_path, int set_headers_flag, apr_size_t *response_len);
61 char *(*chxj_serf_get)(request_rec *r, apr_pool_t *ppool, const char *url_path, int set_headers_flag, apr_size_t *response_len) = default_chxj_serf_get;
62 char *default_chxj_serf_post(request_rec *r, apr_pool_t *ppool, const char *url_path, char *post_data, apr_size_t post_data_len, int set_headers_flag, apr_size_t *response_len, int *response_code);
63 char *(*chxj_serf_post)(request_rec *r, apr_pool_t *ppool, const char *url_path, char *post_data, apr_size_t post_data_len, int set_headers_flag, apr_size_t *response_len, int *response_code) = default_chxj_serf_post;
64 apr_table_t *default_chxj_serf_head(request_rec *r, apr_pool_t *ppool, const char *url_path, int *response_code);
65 apr_table_t *(*chxj_serf_head)(request_rec *r, apr_pool_t *ppool, const char *url_path, int *response_code) = default_chxj_serf_head;
66
67
68 void
69 s_init(apr_pool_t *ppool, apr_pool_t **pool)
70 {
71   apr_pool_create(pool, ppool);
72   apr_atomic_init(*pool);
73 }
74
75
76
77 static serf_bucket_t *
78 s_connection_setup(apr_socket_t *skt, void *setup_ctx, apr_pool_t *UNUSED(pool))
79 {
80   serf_bucket_t  *c;
81   app_ctx_t      *ctx = (app_ctx_t *)setup_ctx;
82
83   c = serf_bucket_socket_create(skt, ctx->bkt_alloc);
84   if (ctx->ssl_flag) {
85     c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
86     if (!ctx->ssl_ctx) {
87       ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c);
88       serf_ssl_use_default_certificates(ctx->ssl_ctx);
89       serf_ssl_server_cert_callback_set(ctx->ssl_ctx, NULL, NULL);
90     }
91     return c;
92   }
93   return c;
94 }
95
96
97 static void 
98 s_connection_closed(serf_connection_t *UNUSED(conn), void *UNUSED(closed_baton), apr_status_t UNUSED(why), apr_pool_t *UNUSED(pool))
99 {
100   /* nothing */
101 }
102
103
104 static serf_bucket_t *
105 s_accept_response(serf_request_t *request, serf_bucket_t *stream, void *UNUSED(acceptor_baton), apr_pool_t *UNUSED(pool))
106 {
107     serf_bucket_alloc_t *bkt_alloc;
108     serf_bucket_t       *c;
109
110     bkt_alloc = serf_request_get_alloc(request);
111     c = serf_bucket_barrier_create(stream, bkt_alloc);
112     return serf_bucket_response_create(c, bkt_alloc);
113 }
114
115
116 static apr_status_t 
117 s_handle_response(serf_request_t *UNUSED(request), serf_bucket_t *response, void *handler_ctx, apr_pool_t *UNUSED(pool))
118 {
119   const char      *data;
120   apr_size_t      len;
121   serf_status_line sl;
122   apr_status_t     rv;
123   handler_ctx_t  *ctx = handler_ctx;
124
125   rv = serf_bucket_response_status(response, &sl);
126   if (rv != APR_SUCCESS) {
127     if (APR_STATUS_IS_EAGAIN(rv)) {
128       return rv;
129     }
130     ctx->rv = rv;
131     apr_atomic_dec32(&ctx->requests_outstanding); 
132     return rv;
133   }
134   ctx->reason = sl.reason;
135   ctx->response_code = sl.code;
136
137   while (1) {
138     rv = serf_bucket_read(response, 2048, &data, &len);
139     if (SERF_BUCKET_READ_ERROR(rv)) {
140       ctx->rv = rv;
141       apr_atomic_dec32(&ctx->requests_outstanding);
142       DBG(ctx->r, "REQ[%X] end of s_handle_response() (ERROR)", (unsigned int)(apr_size_t)ctx->r);
143       return rv;
144     }
145     if (APR_STATUS_IS_EAGAIN(rv)) {
146       /* 0 byte return if EAGAIN returned. */
147       DBG(ctx->r, "REQ[%X] end of s_handle_response() (EAGAIN) len:[%d]", (unsigned int)(apr_size_t)ctx->r, (int)len);
148       return rv;
149     }
150
151     if (len > 0) {
152       if (! ctx->response) {
153         ctx->response = apr_palloc(ctx->pool, len);
154         ctx->response[0] = 0;
155         ctx->response_len = 0;
156       }
157       else {
158         char *tmp = apr_palloc(ctx->pool, ctx->response_len);
159         memcpy(tmp, ctx->response, ctx->response_len);
160         ctx->response = apr_palloc(ctx->pool, ctx->response_len + len);
161         memcpy(ctx->response, tmp, ctx->response_len);
162       }
163       memcpy(&ctx->response[ctx->response_len], data, len);
164       ctx->response_len += len;
165       ctx->response[ctx->response_len] = 0;
166     }
167     
168     if (APR_STATUS_IS_EOF(rv)) {
169       serf_bucket_t *hdrs;
170       char *tmp_headers = "";
171       hdrs = serf_bucket_response_get_headers(response);
172       while (1) {
173         rv = serf_bucket_read(hdrs, 2048, &data, &len);
174         if (SERF_BUCKET_READ_ERROR(rv))
175           return rv;
176         tmp_headers = apr_pstrcat(ctx->pool, tmp_headers, apr_psprintf(ctx->pool , "%.*s", (unsigned int)len, data), NULL);
177         if (APR_STATUS_IS_EOF(rv)) {
178           break;
179         }
180       }
181       ctx->headers_out = apr_table_make(ctx->pool, 0);
182
183       char *pstat;
184       char *pair = NULL;
185       for (;;) {
186         pair = apr_strtok(tmp_headers, "\n", &pstat);
187         if (!pair) break;
188         tmp_headers = NULL;
189         char *key;
190         char *val;
191
192         char *tpair = apr_pstrdup(ctx->pool, pair);
193         key = tpair;
194         val = strchr(tpair, ':');
195         if (val) {
196           *val = 0;
197           val++;
198           key = qs_trim_string(ctx->pool, key);
199           val = qs_trim_string(ctx->pool, val);
200           DBG(ctx->r, "key:[%s], val:[%s]", key, val);
201           apr_table_add(ctx->headers_out, key, val);
202         }
203       }
204       ctx->rv = APR_SUCCESS;
205       apr_atomic_dec32(&ctx->requests_outstanding);
206       DBG(ctx->r, "REQ[%X] end of s_handle_response()(NORMAL)", (unsigned int)(apr_size_t)ctx->r);
207       return APR_EOF;
208     }
209
210     if (APR_STATUS_IS_EAGAIN(rv)) {
211       DBG(ctx->r, "REQ[%X] end of s_handle_response() (EAGAIN)", (unsigned int)(apr_size_t)ctx->r);
212       return rv;
213     }
214   }
215 }
216
217 static apr_status_t 
218 s_setup_request(serf_request_t           *request,
219                 void                     *setup_ctx,
220                 serf_bucket_t            **req_bkt,
221                 serf_response_acceptor_t *acceptor,
222                 void                     **acceptor_ctx,
223                 serf_response_handler_t  *handler,
224                 void                     **handler_ctx,
225                 apr_pool_t               *UNUSED(pool))
226 {
227   handler_ctx_t *ctx = setup_ctx;
228   serf_bucket_t *hdrs_bkt;
229   serf_bucket_t *body_bkt = NULL;
230   request_rec *r = ctx->r;
231   int ii;
232
233   if (ctx->post_data) {
234     body_bkt = serf_bucket_simple_create(ctx->post_data, ctx->post_data_len, NULL, NULL, serf_request_get_alloc(request));
235   }
236
237   *req_bkt = serf_bucket_request_create(ctx->method, ctx->path, body_bkt, serf_request_get_alloc(request));
238   hdrs_bkt = serf_bucket_request_get_headers(*req_bkt);
239
240
241   apr_array_header_t *headers = (apr_array_header_t*)apr_table_elts(r->headers_in);
242   apr_table_entry_t  *hentryp = (apr_table_entry_t*)headers->elts;
243   for (ii=headers->nelts-1; ii>=0; ii--) {
244     DBG(ctx->r, "REQ[%X] REQUEST PREV key:[%s], val:[%s]", (unsigned int)(apr_size_t)ctx->r, hentryp[ii].key, hentryp[ii].val);
245     serf_bucket_headers_setc(hdrs_bkt, hentryp[ii].key, (hentryp[ii].val) ? hentryp[ii].val : "");
246     DBG(ctx->r, "REQ[%X] REQUEST AFTER key:[%s], val:[%s]", (unsigned int)(apr_size_t)ctx->r, hentryp[ii].key, hentryp[ii].val);
247   }
248   if (ctx->post_data) {
249     DBG(ctx->r, "REQ[%X] REQUEST PREV key:[%s], val:[%s]", (unsigned int)(apr_size_t)ctx->r, "X-Chxj-Forward", "Done");
250     serf_bucket_headers_setc(hdrs_bkt, "X-Chxj-Forward", "Done");
251     DBG(ctx->r, "REQ[%X] REQUEST AFTER key:[%s], val:[%s]", (unsigned int)(apr_size_t)ctx->r, "X-Chxj-Forward", "Done");
252     DBG(ctx->r, "REQ[%X] REQUEST PREV key:[%s], val:[%s]", (unsigned int)(apr_size_t)ctx->r, "X-Chxj-Content-Length", apr_psprintf(r->pool, "%" APR_SIZE_T_FMT, ctx->post_data_len));
253     serf_bucket_headers_setc(hdrs_bkt, "X-Chxj-Content-Length", apr_psprintf(r->pool, "%" APR_SIZE_T_FMT , ctx->post_data_len));
254     DBG(ctx->r, "REQ[%X] REQUEST AFTER key:[%s], val:[%s]", (unsigned int)(apr_size_t)ctx->r, "X-Chxj-Content-Length", apr_psprintf(r->pool, "%" APR_SIZE_T_FMT, ctx->post_data_len));
255   }
256   DBG(ctx->r, "REQ[%X] REQUEST Content-Length:[%s]", (unsigned int)(apr_size_t)r, serf_bucket_headers_get(hdrs_bkt, "Content-Length"));
257
258   apr_atomic_inc32(&(ctx->requests_outstanding));
259   if (ctx->acceptor_ctx->ssl_flag) {
260     serf_bucket_alloc_t *req_alloc;
261     app_ctx_t *app_ctx = ctx->acceptor_ctx;
262
263     req_alloc = serf_request_get_alloc(request);
264
265     if (app_ctx->ssl_ctx == NULL) {
266       *req_bkt = serf_bucket_ssl_encrypt_create(*req_bkt, NULL, app_ctx->bkt_alloc);
267       app_ctx->ssl_ctx = serf_bucket_ssl_encrypt_context_get(*req_bkt);
268     }
269     else {
270       *req_bkt = serf_bucket_ssl_encrypt_create(*req_bkt, app_ctx->ssl_ctx, app_ctx->bkt_alloc);
271     }
272   }
273   *acceptor       = ctx->acceptor;
274   *acceptor_ctx   = ctx->acceptor_ctx;
275   *handler        = ctx->handler;
276   *handler_ctx    = ctx;
277
278   return APR_SUCCESS;
279 }
280
281 char *
282 default_chxj_serf_get(request_rec *r, apr_pool_t *ppool, const char *url_path, int set_headers_flag, apr_size_t *response_len)
283 {
284   apr_pool_t *pool;
285   apr_uri_t url;
286   apr_status_t rv;
287   apr_sockaddr_t *address = NULL;
288
289   serf_context_t *context;
290   serf_connection_t *connection;
291
292   app_ctx_t app_ctx;
293   handler_ctx_t handler_ctx;
294   char *ret;
295
296
297   s_init(ppool, &pool);
298
299   apr_uri_parse(pool, url_path, &url);
300   if (!url.port) {
301     url.port = apr_uri_port_of_scheme(url.scheme);
302   }
303   if (!url.port) {
304     url.port = 80;
305   }
306   if (!url.path) {
307     url.path = "/";
308   }
309   if (!url.hostname) {
310     url.hostname = "localhost";
311   }
312   if (url.query) {
313     url.path = apr_psprintf(pool, "%s?%s", url.path, url.query);
314   }
315
316   rv = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool);
317   if (rv != APR_SUCCESS) {
318     char buf[256];
319     ERR(r, "REQ[%X] %s:%d apr_sockaddr_info_get() failed: rv:[%d|%s] - Please check DNS settings.", 
320            (unsigned int)(apr_size_t)r, __FILE__,__LINE__, rv, apr_strerror(rv, buf, 256));
321     return NULL;
322   }
323   memset(&app_ctx, 0, sizeof(app_ctx_t));
324
325   app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
326   if (strcasecmp(url.scheme, "https") == 0) {
327     app_ctx.ssl_flag = 1;
328   }
329
330   context = serf_context_create(pool);
331   connection = serf_connection_create(context, address, s_connection_setup, &app_ctx, s_connection_closed, &app_ctx, pool);
332
333   memset(&handler_ctx, 0, sizeof(handler_ctx_t));
334   handler_ctx.requests_outstanding = 0;
335   handler_ctx.host = url.hostinfo;
336   handler_ctx.method = "GET";
337   handler_ctx.path = url.path;
338   handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
339   if (!handler_ctx.user_agent) {
340     handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
341   }
342   handler_ctx.post_data = NULL;
343   handler_ctx.post_data_len = 0;
344
345   handler_ctx.acceptor     = s_accept_response;
346   handler_ctx.acceptor_ctx = &app_ctx;
347   handler_ctx.handler      = s_handle_response;
348   handler_ctx.pool         = pool;
349   handler_ctx.r            = r;
350   handler_ctx.response_len = 0;
351   handler_ctx.response     = NULL;
352
353   serf_connection_request_create(connection, s_setup_request, &handler_ctx);
354
355   while (1) {
356     rv = serf_context_run(context, SERF_DURATION_FOREVER, pool);
357     if (APR_STATUS_IS_TIMEUP(rv))
358       continue;
359     if (rv) {
360       char buf[200];
361       ERR(r, "Error running context: (%d) %s\n", rv, apr_strerror(rv, buf, sizeof(buf)));
362       break;
363     }
364     if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) {
365       if (handler_ctx.rv != APR_SUCCESS) {
366         char buf[200];
367         ERR(r, "Error running context: (%d) %s\n", handler_ctx.rv, apr_strerror(handler_ctx.rv, buf, sizeof(buf)));
368       }
369       break;
370     }
371   }
372
373   serf_connection_close(connection);
374   ret = apr_pstrdup(ppool, handler_ctx.response);
375   if (set_headers_flag) {
376     r->headers_out = apr_table_copy(pool, handler_ctx.headers_out);
377     *response_len = handler_ctx.response_len;
378     char *contentType = (char *)apr_table_get(handler_ctx.headers_out, "Content-Type");
379     if (contentType) {
380       chxj_set_content_type(r, contentType);
381     }
382   }
383   return ret;
384 }
385
386
387 char *
388 default_chxj_serf_post(request_rec *r, apr_pool_t *ppool, const char *url_path, char *post_data, apr_size_t post_data_len, int set_headers_flag, apr_size_t *response_len, int *response_code)
389 {
390   apr_pool_t *pool;
391   apr_uri_t url;
392   apr_status_t rv;
393   apr_sockaddr_t *address = NULL;
394
395   serf_context_t *context;
396   serf_connection_t *connection;
397
398   app_ctx_t app_ctx;
399   handler_ctx_t handler_ctx;
400   char *ret;
401
402   DBG(r, "REQ:[%X] start chxj_serf_post()", (unsigned int)(apr_size_t)r);
403
404
405   s_init(ppool, &pool);
406
407   apr_uri_parse(pool, url_path, &url);
408   if (!url.port) {
409     url.port = apr_uri_port_of_scheme(url.scheme);
410   }
411   if (!url.port) {
412     url.port = 80;
413   }
414   if (!url.path) {
415     url.path = "/";
416   }
417   if (!url.hostname) {
418     url.hostname = "localhost";
419   }
420   if (url.query) {
421     url.path = apr_psprintf(pool, "%s?%s", url.path, url.query);
422   }
423
424   rv = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool);
425   if (rv != APR_SUCCESS) {
426     char buf[256];
427     ERR(r, "apr_sockaddr_info_get() failed: rv:[%d|%s]", rv, apr_strerror(rv, buf, 256));
428     return NULL;
429   }
430   memset(&app_ctx, 0, sizeof(app_ctx_t));
431
432   app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
433   if (strcasecmp(url.scheme, "https") == 0) {
434     app_ctx.ssl_flag = 1;
435   }
436
437   context = serf_context_create(pool);
438   connection = serf_connection_create(context, address, s_connection_setup, &app_ctx, s_connection_closed, &app_ctx, pool);
439
440   memset(&handler_ctx, 0, sizeof(handler_ctx_t));
441   handler_ctx.requests_outstanding = 0;
442   handler_ctx.host = url.hostinfo;
443   handler_ctx.method = "POST";
444   handler_ctx.path = url.path;
445   handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
446   if (! handler_ctx.user_agent) {
447     handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
448   }
449   handler_ctx.post_data = post_data;
450   handler_ctx.post_data_len = post_data_len;
451
452   handler_ctx.acceptor     = s_accept_response;
453   handler_ctx.acceptor_ctx = &app_ctx;
454   handler_ctx.handler      = s_handle_response;
455   handler_ctx.pool         = pool;
456   handler_ctx.r            = r;
457   handler_ctx.response_len = 0;
458   handler_ctx.response     = NULL;
459
460   serf_connection_request_create(connection, s_setup_request, &handler_ctx);
461
462   while (1) {
463     rv = serf_context_run(context, SERF_DURATION_FOREVER, pool);
464     if (APR_STATUS_IS_TIMEUP(rv))
465       continue;
466     if (rv) {
467       char buf[200];
468       ERR(r, "Error running context: (%d) %s\n", rv, apr_strerror(rv, buf, sizeof(buf)));
469       break;
470     }
471     if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) {
472       if (handler_ctx.rv != APR_SUCCESS) {
473         char buf[200];
474         ERR(r, "Error running context: (%d) %s\n", handler_ctx.rv, apr_strerror(handler_ctx.rv, buf, sizeof(buf)));
475       }
476       break;
477     }
478   }
479
480   DBG(r, "end of serf request");
481   DBG(r, "response_code:[%d]", handler_ctx.response_code);
482   DBG(r, "response:[%s][%" APR_SIZE_T_FMT "]", handler_ctx.response, handler_ctx.response_len);
483   serf_connection_close(connection);
484   if (handler_ctx.response) {
485     ret = apr_palloc(ppool, handler_ctx.response_len + 1);
486     memset(ret, 0, handler_ctx.response_len + 1);
487     memcpy(ret, handler_ctx.response, handler_ctx.response_len);
488   }
489   else {
490     ret = apr_pstrdup(ppool, "");
491   }
492   if (set_headers_flag && !rv) {
493     r->headers_out = apr_table_copy(pool, handler_ctx.headers_out);
494     *response_len = handler_ctx.response_len;
495     char *contentType = (char *)apr_table_get(handler_ctx.headers_out, "Content-Type");
496     if (contentType) {
497       DBG(r, "response content type[%s]", contentType);
498       chxj_set_content_type(r, apr_pstrdup(r->pool, contentType));
499     }
500   }
501   if (rv) {
502     *response_len = 0;
503   }
504   *response_code = handler_ctx.response_code;
505   DBG(r, "REQ:[%X] end chxj_serf_post()", (unsigned int)(apr_size_t)r);
506   return ret;
507 }
508
509
510 apr_table_t *
511 default_chxj_serf_head(request_rec *r, apr_pool_t *ppool, const char *url_path, int *response_code)
512 {
513   apr_pool_t *pool;
514   apr_uri_t url;
515   apr_status_t rv;
516   apr_sockaddr_t *address = NULL;
517
518   serf_context_t *context;
519   serf_connection_t *connection;
520
521   app_ctx_t app_ctx;
522   handler_ctx_t handler_ctx;
523   char *ret;
524
525   DBG(r, "REQ:[%X] start chxj_serf_head()", (unsigned int)(apr_size_t)r);
526
527
528   s_init(ppool, &pool);
529
530   apr_uri_parse(pool, url_path, &url);
531   if (!url.port) {
532     url.port = apr_uri_port_of_scheme(url.scheme);
533   }
534   if (!url.port) {
535     url.port = 80;
536   }
537   if (!url.path) {
538     url.path = "/";
539   }
540   if (!url.hostname) {
541     url.hostname = "localhost";
542   }
543   if (url.query) {
544     url.path = apr_psprintf(pool, "%s?%s", url.path, url.query);
545   }
546
547   rv = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool);
548   if (rv != APR_SUCCESS) {
549     char buf[256];
550     ERR(r, "apr_sockaddr_info_get() failed: rv:[%d|%s]", rv, apr_strerror(rv, buf, 256));
551     return NULL;
552   }
553   memset(&app_ctx, 0, sizeof(app_ctx_t));
554
555   app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
556   if (strcasecmp(url.scheme, "https") == 0) {
557     app_ctx.ssl_flag = 1;
558   }
559
560   context = serf_context_create(pool);
561   connection = serf_connection_create(context, address, s_connection_setup, &app_ctx, s_connection_closed, &app_ctx, pool);
562
563   memset(&handler_ctx, 0, sizeof(handler_ctx_t));
564   handler_ctx.requests_outstanding = 0;
565   handler_ctx.host = url.hostinfo;
566   /*========================================================================================================*/
567   /* XXX Maybe, libserf doesn't support the HEAD request. Because the part body is waited for with polling. */
568   /*========================================================================================================*/
569   handler_ctx.method = "GET";
570   handler_ctx.path = url.path;
571   handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
572   if (! handler_ctx.user_agent) {
573     handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
574   }
575   handler_ctx.post_data     = NULL;
576   handler_ctx.post_data_len = 0;
577
578   handler_ctx.acceptor     = s_accept_response;
579   handler_ctx.acceptor_ctx = &app_ctx;
580   handler_ctx.handler      = s_handle_response;
581   handler_ctx.pool         = pool;
582   handler_ctx.r            = r;
583   handler_ctx.response_len = 0;
584   handler_ctx.response     = NULL;
585
586   serf_connection_request_create(connection, s_setup_request, &handler_ctx);
587
588   while (1) {
589     rv = serf_context_run(context, SERF_DURATION_FOREVER, pool);
590     if (APR_STATUS_IS_TIMEUP(rv))
591       continue;
592     if (rv) {
593       char buf[200];
594       ERR(r, "Error running context: (%d) %s\n", rv, apr_strerror(rv, buf, sizeof(buf)));
595       break;
596     }
597     if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) {
598       if (handler_ctx.rv != APR_SUCCESS) {
599         char buf[200];
600         ERR(r, "Error running context: (%d) %s\n", handler_ctx.rv, apr_strerror(handler_ctx.rv, buf, sizeof(buf)));
601       }
602       break;
603     }
604   }
605
606   DBG(r, "end of serf request");
607   DBG(r, "response_code:[%d]", handler_ctx.response_code);
608   DBG(r, "response:[%s][%" APR_SIZE_T_FMT "]", handler_ctx.response, handler_ctx.response_len);
609   serf_connection_close(connection);
610   if (handler_ctx.response) {
611     ret = apr_pstrdup(ppool, handler_ctx.response);
612   }
613   else {
614     ret = apr_pstrdup(ppool, "");
615   }
616   *response_code = handler_ctx.response_code;
617   DBG(r, "REQ:[%X] end chxj_serf_post()", (unsigned int)(apr_size_t)r);
618   return handler_ctx.headers_out;
619 }
620 /*
621  * vim:ts=2 et
622  */