/Users/maurits/Documents/studie/afstuderen/biosphere/daemon/http.c

Go to the documentation of this file.
00001 /*
00002  * Author: MA Hartman
00003  * Date: mar 21, 2007
00004  * 
00005  * Function:
00006  * HTTP handling code for the daemon.
00007  * 
00008  * License information:
00009  * 
00010  * Copyright (c) 2006 Maurits Hartman
00011  *
00012  * Permission is hereby granted, free of charge, to any person
00013  * obtaining a copy of this software and associated documentation
00014  * files (the "Software"), to deal in the Software without
00015  * restriction, including without limitation the rights to use,
00016  * copy, modify, merge, publish, distribute, sublicense, and/or sell
00017  * copies of the Software, and to permit persons to whom the
00018  * Software is furnished to do so, subject to the following
00019  * conditions:
00020  * 
00021  * The above copyright notice and this permission notice shall be
00022  * included in all copies or substantial portions of the Software.
00023  * 
00024  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00026  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00027  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00028  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00029  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00030  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00031  * OTHER DEALINGS IN THE SOFTWARE.
00032  * 
00033  */
00034  
00035 #include "http.h"
00036 #include "settings.h"
00037 #include "service.h"
00038 #include <copy.h>
00039 #include <xml.h>
00040 
00041 #include <apr_strings.h>
00042 #include <string.h>
00043 #include <stdlib.h>
00044 #include <stdio.h>
00045 
00046 
00047 static char *get_remote_endpoint(apr_socket_t *sock, apr_pool_t *mp)
00048 {
00049         char *remote_ipaddr;
00050         /* apr_port_t remote_port; */
00051         apr_sockaddr_t *remote_sa;
00052         
00053         apr_socket_addr_get(&remote_sa, APR_REMOTE, sock);
00054         apr_sockaddr_ip_get(&remote_ipaddr, remote_sa);
00055         /* remote_port = remote_sa->port; */
00056         
00057         /*return apr_psprintf(mp, "%s:%u", remote_ipaddr, remote_port); */
00058         return remote_ipaddr;
00059 }
00060 
00061 
00062 bs_status handle_http_get(apr_socket_t *sock, apr_pool_t *mp)
00063 {
00064         apr_status_t rv;
00065         bs_status rv2;
00066         bs_definition *def;
00067         char *contentbuf, *headerbuf, timebuf[APR_RFC822_DATE_LEN + 1];
00068         char *remote_client;
00069         apr_size_t len;
00070         bs_uint64 size;
00071         
00072         /* Gather all the definitions and translate them to XML: */
00073         remote_client = get_remote_endpoint(sock, mp);
00074         printf("Handling incoming HTTP GET request from %s\n", remote_client);
00075         rv2 = get_services(&def, mp);
00076         if (rv2 != BS_OK){
00077                 send_http_error(sock, "HTTP/1.0 500 Internal Server Error", mp);
00078                 fprintf(stderr, "%d Error while gathering services\n", rv2);
00079                 return BS_ERROR;
00080         }
00081         rv2 = xlate_definition_to_xml(&contentbuf, &size, def, mp);
00082         if (rv2 != BS_OK){
00083                 send_http_error(sock, "HTTP/1.0 500 Internal Server Error", mp);
00084                 fprintf(stderr, "%d Error while creating WSDL of services\n", rv2);
00085                 return BS_ERROR;
00086         }
00087         
00088         /* Create the HTTP headers and send: */
00089         apr_rfc822_date(timebuf, apr_time_now());
00090         headerbuf = apr_psprintf(mp,
00091                         "HTTP/1.0 200 OK\r\n"
00092                         "Date: %s\r\n"
00093                         "Server: " BIOSPHERE_VERSION_STRING "\r\n"
00094                         "Content-Length: %" BS_UINT64_FMT "\r\n"
00095                         "Content-Type: application/wsdl+xml\r\n"
00096                         "Content-Disposition: attachment; filename=\"services.wsdl\"\r\n\r\n",
00097                         timebuf, size);
00098         headerbuf = apr_pstrcat(mp, headerbuf, contentbuf, NULL);
00099         len = strlen(headerbuf);
00100         rv = apr_socket_send(sock, headerbuf, &len);
00101         if (rv != APR_SUCCESS || len == 0) {
00102                 char err[256];
00103         apr_strerror(rv, err, sizeof(err));
00104                 fprintf(stderr, "Error while sending data: %s\n", err);
00105                 return BS_ERROR;
00106         }
00107         
00108         return BS_OK;
00109 }
00110 
00111 
00119 static bs_status get_remaining_content(apr_socket_t *sock, char **result,
00120                 const char *initial, unsigned size, bs_uint64 remaining,
00121                 apr_pool_t *mp)
00122 {
00123         char *collect;
00124         char buf[HTTP_BUFFER_SIZE];
00125         apr_size_t buflen;
00126 
00127         /* Continuously try to receive the remaining data: */
00128         collect = apr_pstrndup(mp, initial, size);
00129         while (remaining > 0) {
00130                 apr_status_t rv;
00131                 
00132                 buflen = sizeof(buf) - 1;
00133                 memset(buf, '\0', sizeof(buf));
00134                 rv = apr_socket_recv(sock, buf, &buflen);
00135                 if (rv == APR_EOF || buflen == 0) {
00136                         apr_socket_close(sock);
00137                         return BS_ERROR;
00138                 }
00139                 
00140                 /* Chop all data more than the specified content-length: */
00141                 if (buflen > remaining) {
00142                         char *tmp;
00143                         tmp = apr_pstrndup(mp, buf, remaining);
00144                         collect = apr_pstrcat(mp, collect, tmp, NULL);
00145                         break;
00146                 }
00147                 else collect = apr_pstrcat(mp, collect, buf, NULL);
00148                 
00149                 remaining -= buflen;
00150         }
00151         
00152         *result = collect;
00153         return BS_OK;
00154 }
00155 
00156 
00162 static bs_status check_for_http_errors(apr_socket_t *sock,
00163                 http_header_info *info, apr_pool_t *mp)
00164 {
00165         if (info->content_length == 0) {
00166                 send_http_error(sock, "HTTP/1.0 411 Length Required", mp);
00167                 return BS_ERROR;
00168         }
00169         else if (info->content_length > BIOSPHERED_MAX_CONTENT_LENGTH) {
00170                 send_http_error(sock, "HTTP/1.0 413 Request Entity Too Large", mp);
00171                 return BS_ERROR;
00172         }
00173         else if (info->content_type == NULL ||
00174                         apr_strnatcmp(info->content_type, "text/xml") != 0) {
00175                 send_http_error(sock, "HTTP/1.0 415 Unsupported Media Type", mp);
00176                 return BS_ERROR;                
00177         }
00178         
00179         return BS_OK;
00180 }
00181 
00182 
00183 bs_status handle_http_post(apr_socket_t *sock, const char *headerbuf,
00184                 apr_size_t headerlen, apr_pool_t *mp)
00185 {
00186         http_header_info *hinfo;
00187         bs_status rv;
00188         apr_status_t rv2;
00189         apr_size_t len;
00190         char *content_buf, *hbuf, *remote_client, timebuf[APR_RFC822_DATE_LEN + 1];
00191         bs_service_request *request = NULL;
00192         bs_service_response *response = NULL;
00193         unsigned type;
00194         bs_uint64 size;
00195         
00196         /* Parse HTTP headers, check content length and other preconditions: */
00197         remote_client = get_remote_endpoint(sock, mp);
00198         /*printf("Handling incoming HTTP POST request from %s\n", remote_client);*/
00199         rv = parse_http_headers(headerbuf, headerlen, &hinfo, mp);
00200         if (rv != BS_OK) {
00201                 fprintf(stderr, "%d Error while parsing HTTP headers\n", rv);
00202                 return rv;
00203         }
00204         rv = check_for_http_errors(sock, hinfo, mp);
00205         if (rv != BS_OK) {
00206                 fprintf(stderr, "%d Error while checking for HTTP errors\n", rv);
00207                 return rv;
00208         }
00209         headerbuf += hinfo->content_offset;
00210         
00211         /* Process the content data into a buffer: */
00212         if (hinfo->content_length < headerlen - hinfo->content_offset)
00213                 content_buf = apr_pstrndup(mp, headerbuf, hinfo->content_length);
00214         else { /* Still some data bound to arrive: */
00215                 bs_uint64 remaining;
00216                 content_buf = apr_pstrndup(mp, headerbuf, headerlen - hinfo->content_offset);
00217                 remaining = hinfo->content_length - headerlen + hinfo->content_offset;
00218                 rv = get_remaining_content(sock, &content_buf, content_buf,
00219                                 headerlen - hinfo->content_offset, remaining, mp);
00220                 if (rv != BS_OK) {
00221                         fprintf(stderr, "%d Unable to receive remaining content\n", rv);
00222                         return rv;
00223                 }
00224         }
00225         
00226         /* Parse the incoming xml data: */
00227         rv = xlate_from_xml(content_buf, strlen(content_buf), (void **) &request, &type, mp);
00228         if (rv != BS_OK || type != SERVICE_REQUEST_FROM_XML) {
00229                 send_http_error(sock, "HTTP/1.0 406 Not Acceptable", mp);
00230                 fprintf(stderr, "%d Error while translating XML service request\n", rv);
00231                 return rv;
00232         }
00233         
00234         
00235         /* Try to handle the service request: */
00236         rv = handle_service_request(request, &response, mp);
00237         if (rv != BS_OK) {
00238                 send_http_error(sock, "HTTP/1.0 503 Service Unavailable", mp);
00239                 fprintf(stderr, "%d Error while handling service request\n", rv);
00240                 delete_response(response);
00241                 return rv;
00242         }
00243         
00244         /* Translate the result to xml: */
00245         rv = xlate_response_to_xml(&content_buf, &size, response, mp);
00246         delete_response(response);
00247         if (rv != BS_OK) {
00248                 send_http_error(sock, "HTTP/1.0 500 Internal Server Error", mp);
00249                 fprintf(stderr, "%d Error while translating service response to XML\n", rv);
00250                 return rv;
00251         }
00252         
00253         /* Create headers and send on its way: */
00254         apr_rfc822_date(timebuf, apr_time_now());
00255         hbuf = apr_psprintf(mp,
00256                         "HTTP/1.0 200 OK\r\n"
00257                         "Date: %s\r\n"
00258                         "Server: " BIOSPHERE_VERSION_STRING "\r\n"
00259                         "Content-Length: %" BS_UINT64_FMT "\r\n"
00260                         "Content-Type: text/xml\r\n\r\n",
00261                         timebuf, size);
00262         hbuf = apr_pstrcat(mp, hbuf, content_buf, NULL);
00263         len = strlen(hbuf);
00264         rv2 = apr_socket_send(sock, hbuf, &len);
00265         if (rv2 != APR_SUCCESS || len == 0) {
00266                 fprintf(stderr, "%d Error while sending service response\n", rv);
00267                 return BS_ERROR;
00268         }
00269         
00270         return BS_OK;
00271 }
00272 
00273 
00274 bs_status send_http_error(apr_socket_t *sock, const char *errstring, apr_pool_t *mp)
00275 {
00276         apr_status_t rv;
00277         char *buf, timebuf[APR_RFC822_DATE_LEN + 1];
00278         apr_size_t len;
00279         
00280         apr_rfc822_date(timebuf, apr_time_now());
00281         buf = apr_psprintf(mp,
00282                         "%s\r\n"
00283                         "Date: %s\r\n"
00284                         "Server: " BIOSPHERE_VERSION_STRING "\r\n\r\n",
00285                         errstring,
00286                         timebuf);
00287         len = strlen(buf);
00288         rv = apr_socket_send(sock, buf, &len);
00289         if (rv != APR_SUCCESS) return BS_ERROR;
00290         
00291         return BS_OK;   
00292 }

Generated on Tue Jul 17 09:50:52 2007 for Bio-SPHERE by  doxygen 1.5.1