Browse Source

working on https

mom040267 11 years ago
parent
commit
0aee63f61e

+ 205 - 0
src/apps/relay/http_server.c

@@ -30,6 +30,26 @@
 
 #include "ns_ioalib_impl.h"
 
+#include "http_server.h"
+
+#include <event2/http.h>
+#include <event2/keyvalq_struct.h>
+
+//////////////////////////////////////
+
+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)) {
@@ -54,3 +74,188 @@ static void write_http_echo(ioa_socket_handle s)
 void handle_http_echo(ioa_socket_handle s) {
 	write_http_echo(s);
 }
+
+///////////////////////////////////////////////
+
+static struct headers_list * post_parse(char *data, size_t data_len)
+{
+	char *post_data = calloc(data_len + 1, sizeof(char));
+	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));
+	ns_bzero(list,sizeof(struct headers_list));
+	while (fsplit != NULL) {
+		char *vmarker = NULL;
+		char *key = strtok_r(fsplit, "=", &vmarker);
+		char *value = strtok_r(NULL, "=", &vmarker);
+		value = value ? value : "";
+		value = evhttp_decode_uri(value);
+		char *p = value;
+		while (*p != '\0') {
+			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;
+}
+
+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));
+					ns_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));
+						ns_bzero(ret->headers,sizeof(struct http_headers));
+						ret->headers->uri_headers = kv;
+					}
+				}
+				evhttp_uri_free(uri);
+
+				if(parse_post) {
+					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));
+							ns_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));
+		ns_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,"POST ") == request) {
+			ret->rtype = HRT_POST;
+			ret = parse_http_request_1(ret,request+5,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;i<h->n;++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;i<h->n;++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;i<h->n;++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 *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);
+		}
+	}
+	return ret;
+}
+
+void free_http_request(struct http_request *request) {
+	if(request) {
+		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);
+	}
+}
+
+///////////////////////////////////////////////

+ 24 - 3
src/apps/relay/http_server.h

@@ -31,17 +31,38 @@
 #ifndef __TURN_HTTP_SERVER__
 #define __TURN_HTTP_SERVER__
 
-#include <stdlib.h>
-#include <stdio.h>
-
 #include "ns_turn_utils.h"
 #include "ns_turn_server.h"
 #include "apputils.h"
 
+#include <stdlib.h>
+#include <stdio.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/////////  HTTP REQUEST //////////
+
+enum _HTTP_REQUEST_TYPE {
+	HRT_UNKNOWN=0,
+	HRT_GET,
+	HRT_POST
+};
+
+typedef enum _HTTP_REQUEST_TYPE HTTP_REQUEST_TYPE;
+
+struct http_headers;
+
+struct http_request {
+	HTTP_REQUEST_TYPE rtype;
+	struct http_headers *headers;
+};
+
+struct http_request* parse_http_request(char* request);
+const char *get_http_header_value(const struct http_request *request, const char* key);
+void free_http_request(struct http_request *request);
+
 ////////////////////////////////////////////
 
 void handle_http_echo(ioa_socket_handle s);

+ 2 - 2
src/apps/relay/ns_ioalib_engine_impl.c

@@ -2601,7 +2601,7 @@ void close_ioa_socket_after_processing_if_necessary(ioa_socket_handle s)
 	if (s && ioa_socket_tobeclosed(s)) {
 
 		if(!(s->session) && !(s->sub_session)) {
-			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s https server socket closed: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)s, get_ioa_socket_type(s), get_ioa_socket_type(s));
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s https server socket closed: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)s, get_ioa_socket_type(s), get_ioa_socket_app_type(s));
 			IOA_CLOSE_SOCKET(s);
 			return;
 		}
@@ -2782,7 +2782,7 @@ static void eventcb_bev(struct bufferevent *bev, short events, void *arg)
 			if(!(s->session) && !(s->sub_session)) {
 				char sraddr[129]="\0";
 				addr_to_string(&(s->remote_addr),(u08bits*)sraddr);
-				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s https server socket closed: 0x%lx, st=%d, sat=%d, remote addr=%s\n", __FUNCTION__,(long)s, get_ioa_socket_type(s), get_ioa_socket_type(s),sraddr);
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s https server socket closed: 0x%lx, st=%d, sat=%d, remote addr=%s\n", __FUNCTION__,(long)s, get_ioa_socket_type(s), get_ioa_socket_app_type(s),sraddr);
 				IOA_CLOSE_SOCKET(s);
 				return;
 			}

+ 7 - 1
src/apps/relay/turn_admin_server.c

@@ -1390,7 +1390,13 @@ static void handle_https(ioa_socket_handle s, ioa_network_buffer_handle nbh) {
 		handle_http_echo(s);
 	} else {
 		if(nbh) {
-			//TODO
+			struct http_request* hr = parse_http_request((char*)ioa_network_buffer_data(nbh));
+			if(!hr) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: wrong HTTPS request (I cannot parse it)\n", __FUNCTION__);
+			} else {
+				//TODO
+				free_http_request(hr);
+			}
 		}
 		write_https_default_page(s);
 	}

+ 2 - 2
src/client/ns_turn_msg.c

@@ -646,9 +646,9 @@ static inline const char* findstr(const char *hay, size_t slen, const char *need
 static inline int is_http_get_inline(const char *s, size_t blen) {
 	if(s && blen>=12) {
 		if((s[0]=='G')&&(s[1]=='E')&&(s[2]=='T')&&(s[3]==' ')) {
-			const char *sp=findstr(s+4,blen-4,"HTTP");
+			const char *sp=findstr(s+4,blen-4," HTTP/");
 			if(sp) {
-				sp += 4;
+				sp += 6;
 				size_t diff_blen = sp-s;
 				if(diff_blen+4 <= blen) {
 					sp=findstr(sp,blen-diff_blen,"\r\n\r\n");

+ 2 - 2
src/server/ns_turn_server.c

@@ -4545,10 +4545,10 @@ static int read_client_connection(turn_turnserver *server,
 					set_ioa_socket_app_type(ss->client_socket,HTTPS_CLIENT_SOCKET);
 					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: %s (%s %s) request: %s\n", __FUNCTION__, proto, get_ioa_socket_cipher(ss->client_socket), get_ioa_socket_ssl_method(ss->client_socket), (char*)ioa_network_buffer_data(in_buffer->nbh));
 					if(server->send_https_socket) {
-						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s socket to be detached: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)ss->client_socket, get_ioa_socket_type(ss->client_socket), get_ioa_socket_type(ss->client_socket));
+						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s socket to be detached: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)ss->client_socket, get_ioa_socket_type(ss->client_socket), get_ioa_socket_app_type(ss->client_socket));
 						ioa_socket_handle new_s = detach_ioa_socket(ss->client_socket);
 						if(new_s) {
-							TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s new detached socket: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)new_s, get_ioa_socket_type(new_s), get_ioa_socket_type(new_s));
+							TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s new detached socket: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)new_s, get_ioa_socket_type(new_s), get_ioa_socket_app_type(new_s));
 							server->send_https_socket(new_s);
 						}
 						ss->to_be_closed = 1;