/* * Copyright (C) 2011, 2012, 2013, 2014 Citrix Systems * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "ns_ioalib_impl.h" #include "http_server.h" #include #include #include ////////////////////////////////////// struct headers_list { size_t n; char **keys; char **values; }; struct http_headers { struct evkeyvalq *uri_headers; struct headers_list *post_headers; }; ////////////////////////////////////// static void write_http_echo(ioa_socket_handle s) { if(s && !ioa_socket_tobeclosed(s)) { SOCKET_APP_TYPE sat = get_ioa_socket_app_type(s); if((sat == HTTP_CLIENT_SOCKET) || (sat == HTTPS_CLIENT_SOCKET)) { ioa_network_buffer_handle nbh_http = ioa_network_buffer_allocate(s->e); size_t len_http = ioa_network_buffer_get_size(nbh_http); uint8_t *data = ioa_network_buffer_data(nbh_http); char data_http[1025]; char content_http[1025]; const char* title = "TURN Server"; snprintf(content_http,sizeof(content_http)-1,"\r\n\r\n \r\n %s\r\n \r\n \r\n %s
use https connection for the admin session\r\n \r\n\r\n",title,title); snprintf(data_http,sizeof(data_http)-1,"HTTP/1.0 200 OK\r\nServer: %s\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: %d\r\n\r\n%.906s",TURN_SOFTWARE,(int)strlen(content_http),content_http); len_http = strlen(data_http); bcopy(data_http,data,len_http); ioa_network_buffer_set_size(nbh_http,len_http); send_data_from_ioa_socket_nbh(s, NULL, nbh_http, TTL_IGNORE, TOS_IGNORE,NULL); } } } void handle_http_echo(ioa_socket_handle s) { write_http_echo(s); } const char* get_http_date_header() { static char buffer_date[256]; static char buffer_header[1025]; static const char* wds[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; static const char* mons[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; time_t now = time(NULL); struct tm *gmtm = gmtime(&now); buffer_header[0]=0; buffer_date[0]=0; if(gmtm) { snprintf(buffer_date,sizeof(buffer_date)-1,"%s, %d %s %d %d:%d:%d GMT",wds[gmtm->tm_wday], gmtm->tm_mday, mons[gmtm->tm_mon], gmtm->tm_year+1900, gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec); buffer_date[sizeof(buffer_date)-1]=0; snprintf(buffer_header,sizeof(buffer_header)-1,"Date: %s\r\n",buffer_date); buffer_header[sizeof(buffer_header)-1]=0; } return buffer_header; } /////////////////////////////////////////////// static struct headers_list * post_parse(char *data, size_t data_len) { while((*data=='\r')||(*data=='\n')) { ++data; --data_len; } if (data_len) { char *post_data = (char*)calloc(data_len + 1, sizeof(char)); if (post_data != NULL) { memcpy(post_data, data, data_len); char *fmarker = NULL; char *fsplit = strtok_r(post_data, "&", &fmarker); struct headers_list *list = (struct headers_list*)malloc(sizeof(struct headers_list)); bzero(list,sizeof(struct headers_list)); while (fsplit != NULL) { char *vmarker = NULL; char *key = strtok_r(fsplit, "=", &vmarker); if (key == NULL) break; else { char *value = strtok_r(NULL, "=", &vmarker); char empty[1]; empty[0]=0; value = value ? value : empty; value = evhttp_decode_uri(value); char *p = value; while (*p) { if (*p == '+') *p = ' '; p++; } list->keys = (char**)realloc(list->keys,sizeof(char*)*(list->n+1)); list->keys[list->n] = strdup(key); list->values = (char**)realloc(list->values,sizeof(char*)*(list->n+1)); list->values[list->n] = value; ++(list->n); fsplit = strtok_r(NULL, "&", &fmarker); } } free(post_data); return list; } } return NULL; } static struct http_request* parse_http_request_1(struct http_request* ret, char* request, int parse_post) { if(ret && request) { char* s = strstr(request," HTTP/"); if(!s) { free(ret); ret = NULL; } else { *s = 0; struct evhttp_uri *uri = evhttp_uri_parse(request); if(!uri) { free(ret); ret = NULL; } else { const char *query = evhttp_uri_get_query(uri); if(query) { struct evkeyvalq* kv = (struct evkeyvalq*)malloc(sizeof(struct evkeyvalq)); bzero(kv,sizeof(struct evkeyvalq)); if(evhttp_parse_query_str(query, kv)<0) { free(ret); ret = NULL; } else { ret->headers = (struct http_headers*)malloc(sizeof(struct http_headers)); bzero(ret->headers,sizeof(struct http_headers)); ret->headers->uri_headers = kv; } } const char *path = evhttp_uri_get_path(uri); if(path && ret) ret->path = strdup(path); evhttp_uri_free(uri); if(parse_post && ret) { char *body = strstr(s+1,"\r\n\r\n"); if(body && body[0]) { if(!ret->headers) { ret->headers = (struct http_headers*)malloc(sizeof(struct http_headers)); bzero(ret->headers,sizeof(struct http_headers)); } ret->headers->post_headers = post_parse(body,strlen(body)); } } } *s = ' '; } } return ret; } struct http_request* parse_http_request(char* request) { struct http_request* ret = NULL; if(request) { ret = (struct http_request*)malloc(sizeof(struct http_request)); bzero(ret,sizeof(struct http_request)); if(strstr(request,"GET ") == request) { ret->rtype = HRT_GET; ret = parse_http_request_1(ret,request+4,0); } else if(strstr(request,"HEAD ") == request) { ret->rtype = HRT_HEAD; ret = parse_http_request_1(ret,request+5,0); } else if(strstr(request,"POST ") == request) { ret->rtype = HRT_POST; ret = parse_http_request_1(ret,request+5,1); } else if(strstr(request,"PUT ") == request) { ret->rtype = HRT_PUT; ret = parse_http_request_1(ret,request+4,1); } else if(strstr(request,"DELETE ") == request) { ret->rtype = HRT_DELETE; ret = parse_http_request_1(ret,request+7,1); } else { free(ret); ret = NULL; } } return ret; } static const char * get_headers_list_value(struct headers_list *h, const char* key) { const char* ret = NULL; if(h && h->keys && h->values && key && key[0]) { size_t i = 0; for(i=0;in;++i) { if(h->keys[i] && !strcmp(key,h->keys[i]) && h->values[i]) { ret = h->values[i]; break; } } } return ret; } static void free_headers_list(struct headers_list *h) { if(h) { if(h->keys) { size_t i = 0; for(i=0;in;++i) { if(h->keys[i]) { free(h->keys[i]); h->keys[i]=NULL; } } free(h->keys); h->keys = NULL; } if(h->values) { size_t i = 0; for(i=0;in;++i) { if(h->values[i]) { free(h->values[i]); h->values[i]=NULL; } } free(h->values); h->values = NULL; } h->n = 0; free(h); } } const char *get_http_header_value(const struct http_request *request, const char* key, const char* default_value) { const char *ret = NULL; if(key && key[0] && request && request->headers) { if(request->headers->uri_headers) { ret = evhttp_find_header(request->headers->uri_headers,key); } if(!ret && request->headers->post_headers) { ret = get_headers_list_value(request->headers->post_headers,key); } } if(!ret) { ret = default_value; } return ret; } void free_http_request(struct http_request *request) { if(request) { if(request->path) { free(request->path); request->path = NULL; } if(request->headers) { if(request->headers->uri_headers) { evhttp_clear_headers(request->headers->uri_headers); free(request->headers->uri_headers); request->headers->uri_headers = NULL; } if(request->headers->post_headers) { free_headers_list(request->headers->post_headers); request->headers->post_headers = NULL; } free(request->headers); request->headers = NULL; } free(request); } } //////////////////////////////////////////// struct str_buffer { size_t capacity; size_t sz; char* buffer; }; struct str_buffer* str_buffer_new(void) { struct str_buffer* ret = (struct str_buffer*)malloc(sizeof(struct str_buffer)); bzero(ret,sizeof(struct str_buffer)); ret->buffer = (char*)malloc(1); ret->buffer[0] = 0; ret->capacity = 1; return ret; } void str_buffer_append(struct str_buffer* sb, const char* str) { if(sb && str && str[0]) { size_t len = strlen(str); while(sb->sz + len + 1 > sb->capacity) { sb->capacity += len + 1024; sb->buffer = (char*)realloc(sb->buffer,sb->capacity); } bcopy(str,sb->buffer+sb->sz,len+1); sb->sz += len; } } void str_buffer_append_sz(struct str_buffer* sb, size_t sz) { char ssz[129]; snprintf(ssz,sizeof(ssz)-1,"%lu",(unsigned long)sz); str_buffer_append(sb,ssz); } void str_buffer_append_sid(struct str_buffer* sb, turnsession_id sid) { char ssz[129]; snprintf(ssz,sizeof(ssz)-1,"%018llu",(unsigned long long)sid); str_buffer_append(sb,ssz); } const char* str_buffer_get_str(const struct str_buffer *sb) { if(sb) { return sb->buffer; } return NULL; } size_t str_buffer_get_str_len(const struct str_buffer *sb) { if(sb) { return sb->sz; } return 0; } void str_buffer_free(struct str_buffer *sb) { if(sb) { free(sb->buffer); free(sb); } } ///////////////////////////////////////////////