Annotation of embedaddon/strongswan/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_http.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2013 Andreas Steffen
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #define _GNU_SOURCE /* for asprintf() */
! 17:
! 18: #include "tnc_ifmap_http.h"
! 19:
! 20: #include <utils/debug.h>
! 21: #include <utils/lexparser.h>
! 22:
! 23: #include <stdio.h>
! 24:
! 25: typedef struct private_tnc_ifmap_http_t private_tnc_ifmap_http_t;
! 26:
! 27: /**
! 28: * Private data of an tnc_ifmap_http_t object.
! 29: */
! 30: struct private_tnc_ifmap_http_t {
! 31:
! 32: /**
! 33: * Public tnc_ifmap_http_t interface.
! 34: */
! 35: tnc_ifmap_http_t public;
! 36:
! 37: /**
! 38: * HTTPS Server URI with https:// prefix removed
! 39: */
! 40: char *uri;
! 41:
! 42: /**
! 43: * Optional base64-encoded username:password for HTTP Basic Authentication
! 44: */
! 45: chunk_t user_pass;
! 46:
! 47: /**
! 48: * HTTP chunked mode
! 49: */
! 50: bool chunked;
! 51:
! 52: };
! 53:
! 54: METHOD(tnc_ifmap_http_t, build, status_t,
! 55: private_tnc_ifmap_http_t *this, chunk_t *in, chunk_t *out)
! 56: {
! 57: char *host, *path, *request, auth[128];
! 58: int len;
! 59:
! 60: /* Duplicate host[/path] string since we are going to manipulate it */
! 61: len = strlen(this->uri) + 2;
! 62: host = malloc(len);
! 63: memset(host, '\0', len);
! 64: strcpy(host, this->uri);
! 65:
! 66: /* Extract appended path or set to root */
! 67: path = strchr(host, '/');
! 68: if (!path)
! 69: {
! 70: path = host + len - 2;
! 71: *path = '/';
! 72: }
! 73:
! 74: /* Use Basic Authentication? */
! 75: if (this->user_pass.len)
! 76: {
! 77: snprintf(auth, sizeof(auth), "Authorization: Basic %.*s\r\n",
! 78: (int)this->user_pass.len, this->user_pass.ptr);
! 79: }
! 80: else
! 81: {
! 82: *auth = '\0';
! 83: }
! 84:
! 85: /* Write HTTP POST request, TODO break up into chunks */
! 86: len = asprintf(&request,
! 87: "POST %s HTTP/1.1\r\n"
! 88: "Host: %.*s\r\n"
! 89: "%s"
! 90: "Content-Type: application/soap+xml;charset=utf-8\r\n"
! 91: "Content-Length: %d\r\n"
! 92: "\r\n"
! 93: "%.*s", path, (int)(path-host), host, auth, (int)in->len,
! 94: (int)in->len, in->ptr);
! 95: free(host);
! 96:
! 97: if (len == -1)
! 98: {
! 99: return FAILED;
! 100: }
! 101: *out = chunk_create(request, len);
! 102: DBG3(DBG_TLS, "sending HTTP POST request %B", out);
! 103:
! 104: return SUCCESS;
! 105: }
! 106:
! 107: static bool process_header(chunk_t *in, bool *chunked, u_int *content_len)
! 108: {
! 109: chunk_t line, version, parameter;
! 110: int code;
! 111: u_int len;
! 112:
! 113: /* Process HTTP protocol version */
! 114: if (!fetchline(in, &line) || !extract_token(&version, ' ', &line) ||
! 115: !match("HTTP/1.1", &version) || sscanf(line.ptr, "%d", &code) != 1)
! 116: {
! 117: DBG1(DBG_TNC, "malformed http response header");
! 118: return FALSE;
! 119: }
! 120: if (code != 200)
! 121: {
! 122: DBG1(DBG_TNC, "http response returns error code %d", code);
! 123: return FALSE;
! 124: }
! 125:
! 126: *content_len = 0;
! 127: *chunked = FALSE;
! 128:
! 129: /* Process HTTP header line by line until the HTTP body is reached */
! 130: while (fetchline(in, &line))
! 131: {
! 132: if (line.len == 0)
! 133: {
! 134: break;
! 135: }
! 136: if (extract_token(¶meter, ':', &line) && eat_whitespace(&line))
! 137: {
! 138: if (match("Content-Length", ¶meter))
! 139: {
! 140: if (sscanf(line.ptr, "%u", &len) == 1)
! 141: {
! 142: *content_len = len;
! 143: }
! 144: }
! 145: else if (match("Transfer-Encoding", ¶meter) &&
! 146: match("chunked", &line))
! 147: {
! 148: *chunked = TRUE;
! 149: }
! 150: }
! 151: }
! 152:
! 153: return TRUE;
! 154: }
! 155:
! 156: METHOD(tnc_ifmap_http_t, process, status_t,
! 157: private_tnc_ifmap_http_t *this, chunk_t *in, chunk_t *out)
! 158: {
! 159: u_int len = 0;
! 160: chunk_t line, out_chunk;
! 161:
! 162: DBG3(DBG_TLS, "receiving HTTP response %B", in);
! 163:
! 164: if (!this->chunked)
! 165: {
! 166: if (!process_header(in, &this->chunked, &len))
! 167: {
! 168: return FAILED;
! 169: }
! 170: }
! 171:
! 172: while (in->len)
! 173: {
! 174: if (this->chunked)
! 175: {
! 176: if (!fetchline(in, &line) || sscanf(line.ptr, "%x", &len) != 1)
! 177: {
! 178: return FAILED;
! 179: }
! 180: DBG3(DBG_TLS, "received HTTP response is chunked (%u bytes)", len);
! 181:
! 182: /* Received last chunk? */
! 183: if (len == 0)
! 184: {
! 185: return SUCCESS;
! 186: }
! 187: }
! 188:
! 189: /* Check size of of remaining HTTP body */
! 190: if (len > in->len)
! 191: {
! 192: DBG1(DBG_TNC, "insufficient data in HTTP body");
! 193: return FAILED;
! 194: }
! 195:
! 196: if (this->chunked)
! 197: {
! 198: out_chunk = *in;
! 199: out_chunk.len = len;
! 200: *out = chunk_cat("mc", *out, out_chunk);
! 201: *in = chunk_skip(*in, len);
! 202: if (!fetchline(in, &line) || line.len > 0)
! 203: {
! 204: return FAILED;
! 205: }
! 206: }
! 207: else
! 208: {
! 209: if (len)
! 210: {
! 211: in->len = len;
! 212: }
! 213: *out = chunk_clone(*in);
! 214: return SUCCESS;
! 215: }
! 216: }
! 217: return NEED_MORE;
! 218: }
! 219:
! 220: METHOD(tnc_ifmap_http_t, destroy, void,
! 221: private_tnc_ifmap_http_t *this)
! 222: {
! 223: free(this);
! 224: }
! 225:
! 226: /**
! 227: * See header
! 228: */
! 229: tnc_ifmap_http_t *tnc_ifmap_http_create(char *uri, chunk_t user_pass)
! 230: {
! 231: private_tnc_ifmap_http_t *this;
! 232:
! 233: INIT(this,
! 234: .public = {
! 235: .build = _build,
! 236: .process = _process,
! 237: .destroy = _destroy,
! 238: },
! 239: .uri = uri,
! 240: .user_pass = user_pass,
! 241: );
! 242:
! 243: return &this->public;
! 244: }
! 245:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>