OSDN Git Service

<br /> for XHTML(i,ez,y!)
[modchxj/mod_chxj.git] / src / chxj_serf.c
index 0a7ceff..1b89ec5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
+ * Copyright (C) 2005-2009 Atsushi Konno All rights reserved.
  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -46,6 +46,7 @@ struct __handler_ctx_t {
 
   apr_status_t rv;
   const char *reason;
+  int response_code;
 
   char *response;
   apr_size_t response_len;
@@ -58,8 +59,10 @@ struct __handler_ctx_t {
 
 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);
 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;
-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);
-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) = default_chxj_serf_post;
+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);
+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;
+apr_table_t *default_chxj_serf_head(request_rec *r, apr_pool_t *ppool, const char *url_path, int *response_code);
+apr_table_t *(*chxj_serf_head)(request_rec *r, apr_pool_t *ppool, const char *url_path, int *response_code) = default_chxj_serf_head;
 
 
 void
@@ -70,12 +73,6 @@ s_init(apr_pool_t *ppool, apr_pool_t **pool)
 }
 
 
-void
-s_term(apr_pool_t *pool)
-{
-  apr_pool_destroy(pool);
-}
-
 
 static serf_bucket_t *
 s_connection_setup(apr_socket_t *skt, void *setup_ctx, apr_pool_t *UNUSED(pool))
@@ -88,6 +85,8 @@ s_connection_setup(apr_socket_t *skt, void *setup_ctx, apr_pool_t *UNUSED(pool))
     c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
     if (!ctx->ssl_ctx) {
       ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c);
+      serf_ssl_use_default_certificates(ctx->ssl_ctx);
+      serf_ssl_server_cert_callback_set(ctx->ssl_ctx, NULL, NULL);
     }
     return c;
   }
@@ -115,7 +114,7 @@ s_accept_response(serf_request_t *request, serf_bucket_t *stream, void *UNUSED(a
 
 
 static apr_status_t 
-s_handle_response(serf_request_t *UNUSED(request), serf_bucket_t *response, void *handler_ctx, apr_pool_t *pool)
+s_handle_response(serf_request_t *UNUSED(request), serf_bucket_t *response, void *handler_ctx, apr_pool_t *UNUSED(pool))
 {
   const char      *data;
   apr_size_t      len;
@@ -133,29 +132,39 @@ s_handle_response(serf_request_t *UNUSED(request), serf_bucket_t *response, void
     return rv;
   }
   ctx->reason = sl.reason;
+  ctx->response_code = sl.code;
 
   while (1) {
     rv = serf_bucket_read(response, 2048, &data, &len);
     if (SERF_BUCKET_READ_ERROR(rv)) {
       ctx->rv = rv;
       apr_atomic_dec32(&ctx->requests_outstanding);
+      DBG(ctx->r, "REQ[%X] end of s_handle_response() (ERROR)", (unsigned int)(apr_size_t)ctx->r);
       return rv;
     }
-
-    if (! ctx->response) {
-      ctx->response = apr_palloc(pool, len);
-      ctx->response[0] = 0;
-      ctx->response_len = 0;
+    if (APR_STATUS_IS_EAGAIN(rv)) {
+      /* 0 byte return if EAGAIN returned. */
+      DBG(ctx->r, "REQ[%X] end of s_handle_response() (EAGAIN) len:[%d]", (unsigned int)(apr_size_t)ctx->r, (int)len);
+      return rv;
     }
-    else {
-      char *tmp = apr_palloc(pool, ctx->response_len);
-      memcpy(tmp, ctx->response, ctx->response_len);
-      ctx->response = apr_palloc(pool, ctx->response_len + len);
-      memcpy(ctx->response, tmp, ctx->response_len);
+
+    if (len > 0) {
+      if (! ctx->response) {
+        ctx->response = apr_palloc(ctx->pool, len);
+        ctx->response[0] = 0;
+        ctx->response_len = 0;
+      }
+      else {
+        char *tmp = apr_palloc(ctx->pool, ctx->response_len);
+        memcpy(tmp, ctx->response, ctx->response_len);
+        ctx->response = apr_palloc(ctx->pool, ctx->response_len + len);
+        memcpy(ctx->response, tmp, ctx->response_len);
+      }
+      memcpy(&ctx->response[ctx->response_len], data, len);
+      ctx->response_len += len;
+      ctx->response[ctx->response_len] = 0;
     }
     
-    memcpy(&ctx->response[ctx->response_len], data, len);
-    ctx->response_len += len;
     if (APR_STATUS_IS_EOF(rv)) {
       serf_bucket_t *hdrs;
       char *tmp_headers = "";
@@ -164,7 +173,7 @@ s_handle_response(serf_request_t *UNUSED(request), serf_bucket_t *response, void
         rv = serf_bucket_read(hdrs, 2048, &data, &len);
         if (SERF_BUCKET_READ_ERROR(rv))
           return rv;
-        tmp_headers = apr_pstrcat(ctx->pool, tmp_headers, apr_psprintf(ctx->pool , "%.*s", len, data), NULL);
+        tmp_headers = apr_pstrcat(ctx->pool, tmp_headers, apr_psprintf(ctx->pool , "%.*s", (unsigned int)len, data), NULL);
         if (APR_STATUS_IS_EOF(rv)) {
           break;
         }
@@ -194,12 +203,12 @@ s_handle_response(serf_request_t *UNUSED(request), serf_bucket_t *response, void
       }
       ctx->rv = APR_SUCCESS;
       apr_atomic_dec32(&ctx->requests_outstanding);
-      DBG(ctx->r, "end of s_handle_response()(NORMAL)");
+      DBG(ctx->r, "REQ[%X] end of s_handle_response()(NORMAL)", (unsigned int)(apr_size_t)ctx->r);
       return APR_EOF;
     }
 
     if (APR_STATUS_IS_EAGAIN(rv)) {
-      DBG(ctx->r, "end of s_handle_response() (EAGAIN)");
+      DBG(ctx->r, "REQ[%X] end of s_handle_response() (EAGAIN)", (unsigned int)(apr_size_t)ctx->r);
       return rv;
     }
   }
@@ -233,13 +242,16 @@ s_setup_request(serf_request_t           *request,
   apr_table_entry_t  *hentryp = (apr_table_entry_t*)headers->elts;
   for (ii=headers->nelts-1; ii>=0; ii--) {
     serf_bucket_headers_setc(hdrs_bkt, hentryp[ii].key, hentryp[ii].val);
-    DBG(ctx->r, "key:[%s], val:[%s]", hentryp[ii].key, hentryp[ii].val);
+    DBG(ctx->r, "REQ[%X] REQUEST key:[%s], val:[%s]", (unsigned int)(apr_size_t)ctx->r, hentryp[ii].key, hentryp[ii].val);
   }
   if (ctx->post_data) {
     serf_bucket_headers_setc(hdrs_bkt, "X-Chxj-Forward", "Done");
-    serf_bucket_headers_setc(hdrs_bkt, "X-Chxj-Content-Length", apr_psprintf(r->pool, "%d", ctx->post_data_len));
+    serf_bucket_headers_setc(hdrs_bkt, "X-Chxj-Content-Length", apr_psprintf(r->pool, "%" APR_SIZE_T_FMT , ctx->post_data_len));
+    DBG(ctx->r, "REQ[%X] REQUEST key:[%s], val:[%s]", (unsigned int)(apr_size_t)ctx->r, "X-Chxj-Forward", "Done");
+    DBG(ctx->r, "REQ[%X] REQUEST 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));
+
   }
-  DBG(ctx->r, "Content-Length:[%s]", serf_bucket_headers_get(hdrs_bkt, "Content-Length"));
+  DBG(ctx->r, "REQ[%X] REQUEST Content-Length:[%s]", (unsigned int)(apr_size_t)r, serf_bucket_headers_get(hdrs_bkt, "Content-Length"));
 
   apr_atomic_inc32(&(ctx->requests_outstanding));
   if (ctx->acceptor_ctx->ssl_flag) {
@@ -295,12 +307,15 @@ default_chxj_serf_get(request_rec *r, apr_pool_t *ppool, const char *url_path, i
   if (!url.hostname) {
     url.hostname = "localhost";
   }
+  if (url.query) {
+    url.path = apr_psprintf(pool, "%s?%s", url.path, url.query);
+  }
 
   rv = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool);
   if (rv != APR_SUCCESS) {
     char buf[256];
-    ERR(r, "apr_sockaddr_info_get() failed: rv:[%d|%s]", rv, apr_strerror(rv, buf, 256));
-    s_term(pool);
+    ERR(r, "REQ[%X] %s:%d apr_sockaddr_info_get() failed: rv:[%d|%s] - Please check DNS settings.", 
+           (unsigned int)(apr_size_t)r, __FILE__,__LINE__, rv, apr_strerror(rv, buf, 256));
     return NULL;
   }
   memset(&app_ctx, 0, sizeof(app_ctx_t));
@@ -318,7 +333,10 @@ default_chxj_serf_get(request_rec *r, apr_pool_t *ppool, const char *url_path, i
   handler_ctx.host = url.hostinfo;
   handler_ctx.method = "GET";
   handler_ctx.path = url.path;
-  handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, "User-Agent");
+  handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
+  if (!handler_ctx.user_agent) {
+    handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
+  }
   handler_ctx.post_data = NULL;
   handler_ctx.post_data_len = 0;
 
@@ -353,20 +371,19 @@ default_chxj_serf_get(request_rec *r, apr_pool_t *ppool, const char *url_path, i
   serf_connection_close(connection);
   ret = apr_pstrdup(ppool, handler_ctx.response);
   if (set_headers_flag) {
-    r->headers_out = apr_table_copy(r->pool, handler_ctx.headers_out);
+    r->headers_out = apr_table_copy(pool, handler_ctx.headers_out);
     *response_len = handler_ctx.response_len;
     char *contentType = (char *)apr_table_get(handler_ctx.headers_out, "Content-Type");
     if (contentType) {
       chxj_set_content_type(r, contentType);
     }
   }
-  s_term(pool);
   return ret;
 }
 
 
 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)
+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)
 {
   apr_pool_t *pool;
   apr_uri_t url;
@@ -380,7 +397,7 @@ default_chxj_serf_post(request_rec *r, apr_pool_t *ppool, const char *url_path,
   handler_ctx_t handler_ctx;
   char *ret;
 
-  DBG(r, "start chxj_serf_post()");
+  DBG(r, "REQ:[%X] start chxj_serf_post()", (unsigned int)(apr_size_t)r);
 
 
   s_init(ppool, &pool);
@@ -398,12 +415,14 @@ default_chxj_serf_post(request_rec *r, apr_pool_t *ppool, const char *url_path,
   if (!url.hostname) {
     url.hostname = "localhost";
   }
+  if (url.query) {
+    url.path = apr_psprintf(pool, "%s?%s", url.path, url.query);
+  }
 
   rv = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool);
   if (rv != APR_SUCCESS) {
     char buf[256];
     ERR(r, "apr_sockaddr_info_get() failed: rv:[%d|%s]", rv, apr_strerror(rv, buf, 256));
-    s_term(pool);
     return NULL;
   }
   memset(&app_ctx, 0, sizeof(app_ctx_t));
@@ -421,7 +440,10 @@ default_chxj_serf_post(request_rec *r, apr_pool_t *ppool, const char *url_path,
   handler_ctx.host = url.hostinfo;
   handler_ctx.method = "POST";
   handler_ctx.path = url.path;
-  handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, "User-Agent");
+  handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
+  if (! handler_ctx.user_agent) {
+    handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
+  }
   handler_ctx.post_data = post_data;
   handler_ctx.post_data_len = post_data_len;
 
@@ -454,11 +476,17 @@ default_chxj_serf_post(request_rec *r, apr_pool_t *ppool, const char *url_path,
   }
 
   DBG(r, "end of serf request");
-  DBG(r, "response:[%s][%d]", handler_ctx.response, handler_ctx.response_len);
+  DBG(r, "response_code:[%d]", handler_ctx.response_code);
+  DBG(r, "response:[%s][%" APR_SIZE_T_FMT "]", handler_ctx.response, handler_ctx.response_len);
   serf_connection_close(connection);
-  ret = apr_pstrdup(ppool, handler_ctx.response);
-  if (set_headers_flag) {
-    r->headers_out = apr_table_copy(r->pool, handler_ctx.headers_out);
+  if (handler_ctx.response) {
+    ret = apr_pstrdup(ppool, handler_ctx.response);
+  }
+  else {
+    ret = apr_pstrdup(ppool, "");
+  }
+  if (set_headers_flag && !rv) {
+    r->headers_out = apr_table_copy(pool, handler_ctx.headers_out);
     *response_len = handler_ctx.response_len;
     char *contentType = (char *)apr_table_get(handler_ctx.headers_out, "Content-Type");
     if (contentType) {
@@ -466,10 +494,125 @@ default_chxj_serf_post(request_rec *r, apr_pool_t *ppool, const char *url_path,
       chxj_set_content_type(r, apr_pstrdup(r->pool, contentType));
     }
   }
-  s_term(pool);
-  DBG(r, "end chxj_serf_post()");
+  if (rv) {
+    *response_len = 0;
+  }
+  *response_code = handler_ctx.response_code;
+  DBG(r, "REQ:[%X] end chxj_serf_post()", (unsigned int)(apr_size_t)r);
   return ret;
 }
+
+
+apr_table_t *
+default_chxj_serf_head(request_rec *r, apr_pool_t *ppool, const char *url_path, int *response_code)
+{
+  apr_pool_t *pool;
+  apr_uri_t url;
+  apr_status_t rv;
+  apr_sockaddr_t *address = NULL;
+
+  serf_context_t *context;
+  serf_connection_t *connection;
+
+  app_ctx_t app_ctx;
+  handler_ctx_t handler_ctx;
+  char *ret;
+
+  DBG(r, "REQ:[%X] start chxj_serf_head()", (unsigned int)(apr_size_t)r);
+
+
+  s_init(ppool, &pool);
+
+  apr_uri_parse(pool, url_path, &url);
+  if (!url.port) {
+    url.port = apr_uri_port_of_scheme(url.scheme);
+  }
+  if (!url.port) {
+    url.port = 80;
+  }
+  if (!url.path) {
+    url.path = "/";
+  }
+  if (!url.hostname) {
+    url.hostname = "localhost";
+  }
+  if (url.query) {
+    url.path = apr_psprintf(pool, "%s?%s", url.path, url.query);
+  }
+
+  rv = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool);
+  if (rv != APR_SUCCESS) {
+    char buf[256];
+    ERR(r, "apr_sockaddr_info_get() failed: rv:[%d|%s]", rv, apr_strerror(rv, buf, 256));
+    return NULL;
+  }
+  memset(&app_ctx, 0, sizeof(app_ctx_t));
+
+  app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
+  if (strcasecmp(url.scheme, "https") == 0) {
+    app_ctx.ssl_flag = 1;
+  }
+
+  context = serf_context_create(pool);
+  connection = serf_connection_create(context, address, s_connection_setup, &app_ctx, s_connection_closed, &app_ctx, pool);
+
+  memset(&handler_ctx, 0, sizeof(handler_ctx_t));
+  handler_ctx.requests_outstanding = 0;
+  handler_ctx.host = url.hostinfo;
+  /*========================================================================================================*/
+  /* XXX Maybe, libserf doesn't support the HEAD request. Because the part body is waited for with polling. */
+  /*========================================================================================================*/
+  handler_ctx.method = "GET";
+  handler_ctx.path = url.path;
+  handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
+  if (! handler_ctx.user_agent) {
+    handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
+  }
+  handler_ctx.post_data     = NULL;
+  handler_ctx.post_data_len = 0;
+
+  handler_ctx.acceptor     = s_accept_response;
+  handler_ctx.acceptor_ctx = &app_ctx;
+  handler_ctx.handler      = s_handle_response;
+  handler_ctx.pool         = pool;
+  handler_ctx.r            = r;
+  handler_ctx.response_len = 0;
+  handler_ctx.response     = NULL;
+
+  serf_connection_request_create(connection, s_setup_request, &handler_ctx);
+
+  while (1) {
+    rv = serf_context_run(context, SERF_DURATION_FOREVER, pool);
+    if (APR_STATUS_IS_TIMEUP(rv))
+      continue;
+    if (rv) {
+      char buf[200];
+      ERR(r, "Error running context: (%d) %s\n", rv, apr_strerror(rv, buf, sizeof(buf)));
+      break;
+    }
+    if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) {
+      if (handler_ctx.rv != APR_SUCCESS) {
+        char buf[200];
+        ERR(r, "Error running context: (%d) %s\n", handler_ctx.rv, apr_strerror(handler_ctx.rv, buf, sizeof(buf)));
+      }
+      break;
+    }
+  }
+
+  DBG(r, "end of serf request");
+  DBG(r, "response_code:[%d]", handler_ctx.response_code);
+  DBG(r, "response:[%s][%" APR_SIZE_T_FMT "]", handler_ctx.response, handler_ctx.response_len);
+  serf_connection_close(connection);
+  if (handler_ctx.response) {
+    ret = apr_pstrdup(ppool, handler_ctx.response);
+  }
+  else {
+    ret = apr_pstrdup(ppool, "");
+  }
+  *response_code = handler_ctx.response_code;
+  DBG(r, "REQ:[%X] end chxj_serf_post()", (unsigned int)(apr_size_t)r);
+  return handler_ctx.headers_out;
+}
 /*
  * vim:ts=2 et
  */