00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "http_common.h"
00036 #include "xml.h"
00037 #include <biosphere.h>
00038
00039 #include <apr_strings.h>
00040 #include <apr_lib.h>
00041 #include <apr_network_io.h>
00042 #include <stdlib.h>
00043
00044
00045 bs_bool received_full_headers(const char *headerbuf)
00046 {
00047 unsigned i;
00048 apr_size_t headerlen;
00049
00050
00051 if (headerbuf == NULL) return FALSE;
00052 else headerlen = strlen(headerbuf);
00053
00054 for (i = 0; i < headerlen - 2; i++) {
00055 if (headerbuf[i] == '\n') {
00056 if (headerbuf[i + 1] == '\r' && headerbuf[i + 2] == '\n')
00057 return TRUE;
00058 else if (headerbuf[i + 1] == '\n')
00059 return TRUE;
00060 }
00061 }
00062 return FALSE;
00063 }
00064
00065
00074 static bs_status extract_http_header_info(char *header,
00075 http_header_info *hinfo, apr_pool_t *mp)
00076 {
00077 char *token, *q;
00078
00079
00080 token = apr_strtok(header, " :\r\n/", &q);
00081 if (apr_strnatcasecmp(token, "Content-Type") == 0) {
00082 token = apr_strtok(NULL, " \r\n", &q);
00083 hinfo->content_type = apr_pstrdup(mp, token);
00084 }
00085 else if (apr_strnatcasecmp(token, "Content-Length") == 0) {
00086 token = apr_strtok(NULL, " \r\n", &q);
00087 hinfo->content_length = apr_strtoi64(token, NULL, 0);
00088 }
00089 else if (apr_strnatcasecmp(token, "User-Agent") == 0) {
00090 token = apr_strtok(NULL, "\r\n", &q);
00091 if (token[0] == ' ') token++;
00092 hinfo->user_agent = apr_pstrdup(mp, token);
00093 }
00094 else if (apr_strnatcmp(token, "HTTP") == 0) {
00095 token = apr_strtok(NULL, " \r\n", &q);
00096 token = apr_strtok(NULL, " \r\n", &q);
00097 if (apr_isdigit(token[0]) && apr_isdigit(token[1]) && apr_isdigit(token[2]))
00098 hinfo->http_code = (bs_uint32) strtol(token, NULL, 0);
00099 }
00100
00101 return BS_OK;
00102 }
00103
00104
00105 bs_status parse_http_headers(const char *headerbuf, apr_size_t headerlen,
00106 http_header_info **info, apr_pool_t *mp)
00107 {
00108 unsigned buf_pos = 0;
00109 http_header_info *hinfo;
00110
00111 hinfo = (http_header_info *) apr_pcalloc(mp, sizeof(http_header_info));
00112
00113
00114 while (1) {
00115 unsigned begin_pos = buf_pos;
00116 char *line = (char *) (headerbuf + buf_pos);
00117 bs_status rv;
00118
00119
00120 while (headerbuf[buf_pos] != '\n' && buf_pos < headerlen) buf_pos++;
00121 line = apr_pstrndup(mp, line, buf_pos - begin_pos);
00122 rv = extract_http_header_info(line, hinfo, mp);
00123 if (rv != BS_OK) return BS_HTTP_ERROR;
00124
00125
00126 if (buf_pos + 2 < headerlen && headerbuf[buf_pos + 1] == '\r' &&
00127 headerbuf[buf_pos + 2] == '\n') {
00128 buf_pos += 3;
00129 break;
00130 }
00131 else if (buf_pos + 1 < headerlen && headerbuf[buf_pos + 1] == '\n') {
00132 buf_pos += 2;
00133 break;
00134 }
00135 else if (buf_pos >= headerlen) return BS_HTTP_ERROR;
00136
00137 buf_pos++;
00138 }
00139
00140
00141 hinfo->content_offset = buf_pos;
00142 if (hinfo->content_length == 0 || hinfo->content_offset > hinfo->content_length)
00143 return BS_HTTP_ERROR;
00144 *info = hinfo;
00145 return BS_OK;
00146 }
00147
00148
00159 static bs_status receive_response(apr_socket_t *sock, char **response_data,
00160 bs_uint64 *length, apr_pool_t *mp)
00161 {
00162 bs_status rv;
00163 http_header_info *info;
00164 char *buf = NULL;
00165 int tries = 4;
00166 bs_uint64 remaining;
00167
00168
00169 while (!received_full_headers(buf) && tries > 0) {
00170 apr_status_t rv2;
00171 apr_size_t len;
00172 char tmpbuf[HTTP_BUFFER_SIZE];
00173
00174
00175 len = sizeof(tmpbuf) - 1;
00176 memset(tmpbuf, '\0', sizeof(tmpbuf));
00177 rv2 = apr_socket_recv(sock, tmpbuf, &len);
00178 if (rv2 != APR_SUCCESS || len == 0) break;
00179
00180 if (!buf) buf = apr_pstrdup(mp, tmpbuf);
00181 else buf = apr_pstrcat(mp, buf, tmpbuf, NULL);
00182 tries--;
00183 }
00184
00185
00186 if (!received_full_headers(buf)) return BS_HTTP_ERROR;
00187 rv = parse_http_headers(buf, strlen(buf), &info, mp);
00188 if (rv != BS_OK || !HTTP_CORRECT(info) || info->content_offset == 0)
00189 return BS_HTTP_ERROR;
00190
00191
00192 buf += info->content_offset;
00193 remaining = info->content_length - strlen(buf);
00194 while (remaining > 0) {
00195 apr_status_t rv2;
00196 apr_size_t len;
00197 char tmpbuf[HTTP_BUFFER_SIZE];
00198
00199
00200 len = (remaining > sizeof(tmpbuf) - 1) ? sizeof(tmpbuf) - 1 : remaining;
00201 memset(tmpbuf, '\0', sizeof(tmpbuf));
00202 rv2 = apr_socket_recv(sock, tmpbuf, &len);
00203 if (rv2 != APR_SUCCESS || len == 0) break;
00204 buf = apr_pstrcat(mp, buf, tmpbuf, NULL);
00205 remaining -= len;
00206 }
00207
00208 *length = strlen(buf);
00209 if (*length != info->content_length) return BS_HTTP_ERROR;
00210
00211 *response_data = buf;
00212 return BS_OK;
00213 }
00214
00215
00216 bs_status connect_and_post(const bs_service_request *request,
00217 bs_service_response **response, const char *addr,
00218 bs_uint16 port, apr_pool_t *mp)
00219 {
00220 bs_status rv;
00221 apr_status_t rv2;
00222 apr_sockaddr_t *sa;
00223 apr_socket_t *sock;
00224 char *buf, *xml, timebuf[APR_RFC822_DATE_LEN + 1];
00225 bs_uint64 size;
00226 apr_size_t size2;
00227 unsigned type;
00228 bs_service_response *resp = NULL;
00229
00230
00231 rv = xlate_request_to_xml(&xml, &size, request, mp);
00232 if (rv != BS_OK) return rv;
00233 apr_rfc822_date(timebuf, apr_time_now());
00234 buf = apr_psprintf(mp,
00235 "POST /service_request HTTP/1.0\r\n"
00236 "User-Agent: " BIOSPHERE_VERSION_STRING "\r\n"
00237 "Date: %s\r\n"
00238 "Content-Length: %" BS_UINT64_FMT "\r\n"
00239 "Content-Type: text/xml\r\n\r\n",
00240 timebuf, size);
00241 buf = apr_pstrcat(mp, buf, xml, NULL);
00242
00243
00244 apr_sockaddr_info_get(&sa, addr, APR_INET, port, 0, mp);
00245 rv2 = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp);
00246 if (rv2 != APR_SUCCESS) return BS_ERROR;
00247 rv2 = apr_socket_connect(sock, sa);
00248 if (rv2 != APR_SUCCESS) return BS_ERROR;
00249 size2 = strlen(buf);
00250 rv2 = apr_socket_send(sock, buf, &size2);
00251 if (rv2 != APR_SUCCESS || size == 0) return BS_ERROR;
00252
00253
00254 rv = receive_response(sock, &buf, &size, mp);
00255 if (rv != BS_OK) return rv;
00256 rv = xlate_from_xml(buf, size, (void **) &resp, &type, mp);
00257 if (rv != BS_OK) return rv;
00258
00259 apr_socket_close(sock);
00260 *response = resp;
00261 return BS_OK;
00262 }
00263
00264
00265 bs_status connect_and_get(bs_definition **result, const char *addr,
00266 bs_uint16 port, apr_pool_t *mp)
00267 {
00268 apr_status_t rv;
00269 apr_sockaddr_t *sa;
00270 apr_socket_t *sock;
00271 apr_size_t len;
00272 char *requestbuf, *xmlbuf, timebuf[APR_RFC822_DATE_LEN + 1];
00273 bs_status rv2;
00274 bs_uint64 size;
00275 unsigned type;
00276 bs_definition *def;
00277
00278
00279 apr_rfc822_date(timebuf, apr_time_now());
00280 requestbuf = apr_psprintf(mp,
00281 "GET /service_definitions HTTP/1.0\r\n"
00282 "User-Agent: " BIOSPHERE_VERSION_STRING "\r\n"
00283 "Date: %s\r\n\r\n",
00284 timebuf);
00285
00286
00287 apr_sockaddr_info_get(&sa, "localhost", APR_INET, port, 0, mp);
00288 rv = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp);
00289 if (rv != APR_SUCCESS) return BS_ERROR;
00290 rv = apr_socket_connect(sock, sa);
00291 if (rv != APR_SUCCESS) return BS_ERROR;
00292 len = strlen(requestbuf);
00293 rv = apr_socket_send(sock, requestbuf, &len);
00294 if (rv != APR_SUCCESS || len == 0) return BS_ERROR;
00295
00296
00297 rv2 = receive_response(sock, &xmlbuf, &size, mp);
00298 if (rv2 != BS_OK) return rv;
00299 rv2 = xlate_from_xml(xmlbuf, size, (void **) &def, &type, mp);
00300 if (rv2 != BS_OK || type != SERVICE_DEF_FROM_XML) return rv;
00301 apr_socket_close(sock);
00302
00303 *result = def;
00304 return BS_OK;
00305 }