File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / upnphttp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:55:57 2012 UTC (12 years, 1 month ago) by misho
Branches: miniupnpd, elwix, MAIN
CVS tags: v1_6elwix, HEAD
miniupnpd 1.6+patches

    1: /* $Id: upnphttp.c,v 1.1.1.2 2012/05/29 12:55:57 misho Exp $ */
    2: /* Project :  miniupnp
    3:  * Website :  http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
    4:  * Author :   Thomas Bernard
    5:  * Copyright (c) 2005-2011 Thomas Bernard
    6:  * This software is subject to the conditions detailed in the
    7:  * LICENCE file included in this distribution.
    8:  * */
    9: #include <stdlib.h>
   10: #include <unistd.h>
   11: #include <stdio.h>
   12: #include <string.h>
   13: #include <sys/types.h>
   14: #include <sys/socket.h>
   15: #include <sys/param.h>
   16: #include <arpa/inet.h>
   17: #include <syslog.h>
   18: #include <ctype.h>
   19: #include "config.h"
   20: #include "upnphttp.h"
   21: #include "upnpdescgen.h"
   22: #include "miniupnpdpath.h"
   23: #include "upnpsoap.h"
   24: #include "upnpevents.h"
   25: 
   26: struct upnphttp * 
   27: New_upnphttp(int s)
   28: {
   29: 	struct upnphttp * ret;
   30: 	if(s<0)
   31: 		return NULL;
   32: 	ret = (struct upnphttp *)malloc(sizeof(struct upnphttp));
   33: 	if(ret == NULL)
   34: 		return NULL;
   35: 	memset(ret, 0, sizeof(struct upnphttp));
   36: 	ret->socket = s;
   37: 	return ret;
   38: }
   39: 
   40: void
   41: CloseSocket_upnphttp(struct upnphttp * h)
   42: {
   43: 	if(close(h->socket) < 0)
   44: 	{
   45: 		syslog(LOG_ERR, "CloseSocket_upnphttp: close(%d): %m", h->socket);
   46: 	}
   47: 	h->socket = -1;
   48: 	h->state = 100;
   49: }
   50: 
   51: void
   52: Delete_upnphttp(struct upnphttp * h)
   53: {
   54: 	if(h)
   55: 	{
   56: 		if(h->socket >= 0)
   57: 			CloseSocket_upnphttp(h);
   58: 		if(h->req_buf)
   59: 			free(h->req_buf);
   60: 		if(h->res_buf)
   61: 			free(h->res_buf);
   62: 		free(h);
   63: 	}
   64: }
   65: 
   66: /* parse HttpHeaders of the REQUEST */
   67: static void
   68: ParseHttpHeaders(struct upnphttp * h)
   69: {
   70: 	char * line;
   71: 	char * colon;
   72: 	char * p;
   73: 	int n;
   74: 	line = h->req_buf;
   75: 	/* TODO : check if req_buf, contentoff are ok */
   76: 	while(line < (h->req_buf + h->req_contentoff))
   77: 	{
   78: 		colon = strchr(line, ':');
   79: 		if(colon)
   80: 		{
   81: 			if(strncasecmp(line, "Content-Length", 14)==0)
   82: 			{
   83: 				p = colon;
   84: 				while(*p < '0' || *p > '9')
   85: 					p++;
   86: 				h->req_contentlen = atoi(p);
   87: 				/*printf("*** Content-Lenght = %d ***\n", h->req_contentlen);
   88: 				printf("    readbufflen=%d contentoff = %d\n",
   89: 					h->req_buflen, h->req_contentoff);*/
   90: 			}
   91: 			else if(strncasecmp(line, "SOAPAction", 10)==0)
   92: 			{
   93: 				p = colon;
   94: 				n = 0;
   95: 				while(*p == ':' || *p == ' ' || *p == '\t')
   96: 					p++;
   97: 				while(p[n]>=' ')
   98: 				{
   99: 					n++;
  100: 				}
  101: 				if((p[0] == '"' && p[n-1] == '"')
  102: 				  || (p[0] == '\'' && p[n-1] == '\''))
  103: 				{
  104: 					p++; n -= 2;
  105: 				}
  106: 				h->req_soapAction = p;
  107: 				h->req_soapActionLen = n;
  108: 			}
  109: #ifdef ENABLE_EVENTS
  110: 			else if(strncasecmp(line, "Callback", 8)==0)
  111: 			{
  112: 				p = colon;
  113: 				while(*p != '<' && *p != '\r' )
  114: 					p++;
  115: 				n = 0;
  116: 				while(p[n] != '>' && p[n] != '\r' )
  117: 					n++;
  118: 				h->req_Callback = p + 1;
  119: 				h->req_CallbackLen = MAX(0, n - 1);
  120: 			}
  121: 			else if(strncasecmp(line, "SID", 3)==0)
  122: 			{
  123: 				p = colon + 1;
  124: 				while(isspace(*p))
  125: 					p++;
  126: 				n = 0;
  127: 				while(!isspace(p[n]))
  128: 					n++;
  129: 				h->req_SID = p;
  130: 				h->req_SIDLen = n;
  131: 			}
  132: 			/* Timeout: Seconds-nnnn */
  133: /* TIMEOUT
  134: Recommended. Requested duration until subscription expires,
  135: either number of seconds or infinite. Recommendation
  136: by a UPnP Forum working committee. Defined by UPnP vendor.
  137:  Consists of the keyword "Second-" followed (without an
  138: intervening space) by either an integer or the keyword "infinite". */
  139: 			else if(strncasecmp(line, "Timeout", 7)==0)
  140: 			{
  141: 				p = colon + 1;
  142: 				while(isspace(*p))
  143: 					p++;
  144: 				if(strncasecmp(p, "Second-", 7)==0) {
  145: 					h->req_Timeout = atoi(p+7);
  146: 				}
  147: 			}
  148: #endif
  149: 		}
  150: 		while(!(line[0] == '\r' && line[1] == '\n'))
  151: 			line++;
  152: 		line += 2;
  153: 	}
  154: }
  155: 
  156: /* very minimalistic 404 error message */
  157: static void
  158: Send404(struct upnphttp * h)
  159: {
  160: /*
  161: 	static const char error404[] = "HTTP/1.1 404 Not found\r\n"
  162: 		"Connection: close\r\n"
  163: 		"Content-type: text/html\r\n"
  164: 		"\r\n"
  165: 		"<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
  166: 		"<BODY><H1>Not Found</H1>The requested URL was not found"
  167: 		" on this server.</BODY></HTML>\r\n";
  168: 	int n;
  169: 	n = send(h->socket, error404, sizeof(error404) - 1, 0);
  170: 	if(n < 0)
  171: 	{
  172: 		syslog(LOG_ERR, "Send404: send(http): %m");
  173: 	}*/
  174: 	static const char body404[] =
  175: 		"<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
  176: 		"<BODY><H1>Not Found</H1>The requested URL was not found"
  177: 		" on this server.</BODY></HTML>\r\n";
  178: 	h->respflags = FLAG_HTML;
  179: 	BuildResp2_upnphttp(h, 404, "Not Found",
  180: 	                    body404, sizeof(body404) - 1);
  181: 	SendResp_upnphttp(h);
  182: 	CloseSocket_upnphttp(h);
  183: }
  184: 
  185: /* very minimalistic 501 error message */
  186: static void
  187: Send501(struct upnphttp * h)
  188: {
  189: /*
  190: 	static const char error501[] = "HTTP/1.1 501 Not Implemented\r\n"
  191: 		"Connection: close\r\n"
  192: 		"Content-type: text/html\r\n"
  193: 		"\r\n"
  194: 		"<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
  195: 		"<BODY><H1>Not Implemented</H1>The HTTP Method "
  196: 		"is not implemented by this server.</BODY></HTML>\r\n";
  197: 	int n;
  198: 	n = send(h->socket, error501, sizeof(error501) - 1, 0);
  199: 	if(n < 0)
  200: 	{
  201: 		syslog(LOG_ERR, "Send501: send(http): %m");
  202: 	}
  203: */
  204: 	static const char body501[] = 
  205: 		"<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
  206: 		"<BODY><H1>Not Implemented</H1>The HTTP Method "
  207: 		"is not implemented by this server.</BODY></HTML>\r\n";
  208: 	h->respflags = FLAG_HTML;
  209: 	BuildResp2_upnphttp(h, 501, "Not Implemented",
  210: 	                    body501, sizeof(body501) - 1);
  211: 	SendResp_upnphttp(h);
  212: 	CloseSocket_upnphttp(h);
  213: }
  214: 
  215: static const char *
  216: findendheaders(const char * s, int len)
  217: {
  218: 	while(len-->0)
  219: 	{
  220: 		if(s[0]=='\r' && s[1]=='\n' && s[2]=='\r' && s[3]=='\n')
  221: 			return s;
  222: 		s++;
  223: 	}
  224: 	return NULL;
  225: }
  226: 
  227: #ifdef HAS_DUMMY_SERVICE
  228: static void
  229: sendDummyDesc(struct upnphttp * h)
  230: {
  231: 	static const char xml_desc[] = "<?xml version=\"1.0\"?>\r\n"
  232: 		"<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">"
  233: 		" <specVersion>"
  234: 		"    <major>1</major>"
  235: 		"    <minor>0</minor>"
  236: 		"  </specVersion>"
  237: 		"  <actionList />"
  238: 		"  <serviceStateTable />"
  239: 		"</scpd>\r\n";
  240: 	BuildResp_upnphttp(h, xml_desc, sizeof(xml_desc)-1);
  241: 	SendResp_upnphttp(h);
  242: 	CloseSocket_upnphttp(h);
  243: }
  244: #endif
  245: 
  246: /* Sends the description generated by the parameter */
  247: static void
  248: sendXMLdesc(struct upnphttp * h, char * (f)(int *))
  249: {
  250: 	char * desc;
  251: 	int len;
  252: 	desc = f(&len);
  253: 	if(!desc)
  254: 	{
  255: 		static const char error500[] = "<HTML><HEAD><TITLE>Error 500</TITLE>"
  256: 		   "</HEAD><BODY>Internal Server Error</BODY></HTML>\r\n";
  257: 		syslog(LOG_ERR, "Failed to generate XML description");
  258: 		h->respflags = FLAG_HTML;
  259: 		BuildResp2_upnphttp(h, 500, "Internal Server Error",
  260: 		                    error500, sizeof(error500)-1);
  261: 	}
  262: 	else
  263: 	{
  264: 		BuildResp_upnphttp(h, desc, len);
  265: 	}
  266: 	SendResp_upnphttp(h);
  267: 	CloseSocket_upnphttp(h);
  268: 	free(desc);
  269: }
  270: 
  271: /* ProcessHTTPPOST_upnphttp()
  272:  * executes the SOAP query if it is possible */
  273: static void
  274: ProcessHTTPPOST_upnphttp(struct upnphttp * h)
  275: {
  276: 	if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
  277: 	{
  278: 		if(h->req_soapAction)
  279: 		{
  280: 			/* we can process the request */
  281: 			syslog(LOG_INFO, "SOAPAction: %.*s",
  282: 		    	   h->req_soapActionLen, h->req_soapAction);
  283: 			ExecuteSoapAction(h, 
  284: 				h->req_soapAction,
  285: 				h->req_soapActionLen);
  286: 		}
  287: 		else
  288: 		{
  289: 			static const char err400str[] =
  290: 				"<html><body>Bad request</body></html>";
  291: 			syslog(LOG_INFO, "No SOAPAction in HTTP headers");
  292: 			h->respflags = FLAG_HTML;
  293: 			BuildResp2_upnphttp(h, 400, "Bad Request",
  294: 			                    err400str, sizeof(err400str) - 1);
  295: 			SendResp_upnphttp(h);
  296: 			CloseSocket_upnphttp(h);
  297: 		}
  298: 	}
  299: 	else
  300: 	{
  301: 		/* waiting for remaining data */
  302: 		h->state = 1;
  303: 	}
  304: }
  305: 
  306: #ifdef ENABLE_EVENTS
  307: /**
  308:  * returns 0 if the callback header value is not valid
  309:  * 1 if it is valid.
  310:  */
  311: static int
  312: checkCallbackURL(struct upnphttp * h)
  313: {
  314: 	char addrstr[48];
  315: 	int ipv6;
  316: 	const char * p;
  317: 	int i;
  318: 
  319: 	if(!h->req_Callback || h->req_CallbackLen < 8)
  320: 		return 0;
  321: 	if(memcmp(h->req_Callback, "http://", 7) != 0)
  322: 		return 0;
  323: 	ipv6 = 0;
  324: 	i = 0;
  325: 	p = h->req_Callback + 7;
  326: 	if(*p == '[') {
  327: 		p++;
  328: 		ipv6 = 1;
  329: 		while(*p != ']' && i < (sizeof(addrstr)-1)
  330: 		      && p < (h->req_Callback + h->req_CallbackLen))
  331: 			addrstr[i++] = *(p++);
  332: 	} else {
  333: 		while(*p != '/' && *p != ':' && i < (sizeof(addrstr)-1)
  334: 		      && p < (h->req_Callback + h->req_CallbackLen))
  335: 			addrstr[i++] = *(p++);
  336: 	}
  337: 	addrstr[i] = '\0';
  338: 	if(ipv6) {
  339: 		struct in6_addr addr;
  340: 		if(inet_pton(AF_INET6, addrstr, &addr) <= 0)
  341: 			return 0;
  342: #ifdef ENABLE_IPV6
  343: 		if(!h->ipv6
  344: 		  || (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr))))
  345: 			return 0;
  346: #else
  347: 		return 0;
  348: #endif
  349: 	} else {
  350: 		struct in_addr addr;
  351: 		if(inet_pton(AF_INET, addrstr, &addr) <= 0)
  352: 			return 0;
  353: #ifdef ENABLE_IPV6
  354: 		if(h->ipv6) {
  355: 			if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6)))
  356: 				return 0;
  357: 			if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4))
  358: 				return 0;
  359: 		} else {
  360: 			if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
  361: 				return 0;
  362: 		}
  363: #else
  364: 		if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
  365: 			return 0;
  366: #endif
  367: 	}
  368: 	return 1;
  369: }
  370: 
  371: static void
  372: ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path)
  373: {
  374: 	const char * sid;
  375: 	syslog(LOG_DEBUG, "ProcessHTTPSubscribe %s", path);
  376: 	syslog(LOG_DEBUG, "Callback '%.*s' Timeout=%d",
  377: 	       h->req_CallbackLen, h->req_Callback, h->req_Timeout);
  378: 	syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID);
  379: 	if(!h->req_Callback && !h->req_SID) {
  380: 		/* Missing or invalid CALLBACK : 412 Precondition Failed.
  381: 		 * If CALLBACK header is missing or does not contain a valid HTTP URL,
  382: 		 * the publisher must respond with HTTP error 412 Precondition Failed*/
  383: 		BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
  384: 		SendResp_upnphttp(h);
  385: 		CloseSocket_upnphttp(h);
  386: 	} else {
  387: 	/* - add to the subscriber list
  388: 	 * - respond HTTP/x.x 200 OK 
  389: 	 * - Send the initial event message */
  390: /* Server:, SID:; Timeout: Second-(xx|infinite) */
  391: 	/* Check that the callback URL is on the same IP as
  392: 	 * the request, and not on the internet, nor on ourself (DOS attack ?) */
  393: 		if(h->req_Callback) {
  394: 			if(checkCallbackURL(h)) {
  395: 				sid = upnpevents_addSubscriber(path, h->req_Callback,
  396: 				                               h->req_CallbackLen, h->req_Timeout);
  397: 				h->respflags = FLAG_TIMEOUT;
  398: 				if(sid) {
  399: 					syslog(LOG_DEBUG, "generated sid=%s", sid);
  400: 					h->respflags |= FLAG_SID;
  401: 					h->req_SID = sid;
  402: 					h->req_SIDLen = strlen(sid);
  403: 				}
  404: 				BuildResp_upnphttp(h, 0, 0);
  405: 			} else {
  406: 				syslog(LOG_WARNING, "Invalid Callback in SUBSCRIBE %.*s",
  407: 	       		       h->req_CallbackLen, h->req_Callback);
  408: 				BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
  409: 			}
  410: 		} else {
  411: 			/* subscription renew */
  412: 			/* Invalid SID
  413: 412 Precondition Failed. If a SID does not correspond to a known,
  414: un-expired subscription, the publisher must respond
  415: with HTTP error 412 Precondition Failed. */
  416: 			if(renewSubscription(h->req_SID, h->req_SIDLen, h->req_Timeout) < 0) {
  417: 				BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
  418: 			} else {
  419: 				h->respflags = FLAG_TIMEOUT;
  420: 				BuildResp_upnphttp(h, 0, 0);
  421: 			}
  422: 		}
  423: 		SendResp_upnphttp(h);
  424: 		CloseSocket_upnphttp(h);
  425: 	}
  426: }
  427: 
  428: static void
  429: ProcessHTTPUnSubscribe_upnphttp(struct upnphttp * h, const char * path)
  430: {
  431: 	syslog(LOG_DEBUG, "ProcessHTTPUnSubscribe %s", path);
  432: 	syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID);
  433: 	/* Remove from the list */
  434: 	if(upnpevents_removeSubscriber(h->req_SID, h->req_SIDLen) < 0) {
  435: 		BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
  436: 	} else {
  437: 		BuildResp_upnphttp(h, 0, 0);
  438: 	}
  439: 	SendResp_upnphttp(h);
  440: 	CloseSocket_upnphttp(h);
  441: }
  442: #endif
  443: 
  444: /* Parse and process Http Query 
  445:  * called once all the HTTP headers have been received. */
  446: static void
  447: ProcessHttpQuery_upnphttp(struct upnphttp * h)
  448: {
  449: 	char HttpCommand[16];
  450: 	char HttpUrl[128];
  451: 	char * HttpVer;
  452: 	char * p;
  453: 	int i;
  454: 	p = h->req_buf;
  455: 	if(!p)
  456: 		return;
  457: 	for(i = 0; i<15 && *p != ' ' && *p != '\r'; i++)
  458: 		HttpCommand[i] = *(p++);
  459: 	HttpCommand[i] = '\0';
  460: 	while(*p==' ')
  461: 		p++;
  462: 	for(i = 0; i<127 && *p != ' ' && *p != '\r'; i++)
  463: 		HttpUrl[i] = *(p++);
  464: 	HttpUrl[i] = '\0';
  465: 	while(*p==' ')
  466: 		p++;
  467: 	HttpVer = h->HttpVer;
  468: 	for(i = 0; i<15 && *p != '\r'; i++)
  469: 		HttpVer[i] = *(p++);
  470: 	HttpVer[i] = '\0';
  471: 	syslog(LOG_INFO, "HTTP REQUEST : %s %s (%s)",
  472: 	       HttpCommand, HttpUrl, HttpVer);
  473: 	ParseHttpHeaders(h);
  474: 	if(strcmp("POST", HttpCommand) == 0)
  475: 	{
  476: 		h->req_command = EPost;
  477: 		ProcessHTTPPOST_upnphttp(h);
  478: 	}
  479: 	else if(strcmp("GET", HttpCommand) == 0)
  480: 	{
  481: 		h->req_command = EGet;
  482: 		if(strcasecmp(ROOTDESC_PATH, HttpUrl) == 0)
  483: 		{
  484: 			sendXMLdesc(h, genRootDesc);
  485: 		}
  486: 		else if(strcasecmp(WANIPC_PATH, HttpUrl) == 0)
  487: 		{
  488: 			sendXMLdesc(h, genWANIPCn);
  489: 		}
  490: 		else if(strcasecmp(WANCFG_PATH, HttpUrl) == 0)
  491: 		{
  492: 			sendXMLdesc(h, genWANCfg);
  493: 		}
  494: #ifdef HAS_DUMMY_SERVICE
  495: 		else if(strcasecmp(DUMMY_PATH, HttpUrl) == 0)
  496: 		{
  497: 			sendDummyDesc(h);
  498: 		}
  499: #endif
  500: #ifdef ENABLE_L3F_SERVICE
  501: 		else if(strcasecmp(L3F_PATH, HttpUrl) == 0)
  502: 		{
  503: 			sendXMLdesc(h, genL3F);
  504: 		}
  505: #endif
  506: #ifdef ENABLE_6FC_SERVICE
  507: 		else if(strcasecmp(WANIP6FC_PATH, HttpUrl) == 0)
  508: 		{
  509: 			sendXMLdesc(h, gen6FC);
  510: 		}
  511: #endif
  512: #ifdef ENABLE_DP_SERVICE
  513: 		else if(strcasecmp(DP_PATH, HttpUrl) == 0)
  514: 		{
  515: 			sendXMLdesc(h, genDP);
  516: 		}
  517: #endif
  518: 		else
  519: 		{
  520: 			syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
  521: 			Send404(h);
  522: 		}
  523: 	}
  524: #ifdef ENABLE_EVENTS
  525: 	else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
  526: 	{
  527: 		h->req_command = ESubscribe;
  528: 		ProcessHTTPSubscribe_upnphttp(h, HttpUrl);
  529: 	}
  530: 	else if(strcmp("UNSUBSCRIBE", HttpCommand) == 0)
  531: 	{
  532: 		h->req_command = EUnSubscribe;
  533: 		ProcessHTTPUnSubscribe_upnphttp(h, HttpUrl);
  534: 	}
  535: #else
  536: 	else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
  537: 	{
  538: 		syslog(LOG_NOTICE, "SUBSCRIBE not implemented. ENABLE_EVENTS compile option disabled");
  539: 		Send501(h);
  540: 	}
  541: #endif
  542: 	else
  543: 	{
  544: 		syslog(LOG_NOTICE, "Unsupported HTTP Command %s", HttpCommand);
  545: 		Send501(h);
  546: 	}
  547: }
  548: 
  549: 
  550: void
  551: Process_upnphttp(struct upnphttp * h)
  552: {
  553: 	char buf[2048];
  554: 	int n;
  555: 	if(!h)
  556: 		return;
  557: 	switch(h->state)
  558: 	{
  559: 	case 0:
  560: 		n = recv(h->socket, buf, 2048, 0);
  561: 		if(n<0)
  562: 		{
  563: 			syslog(LOG_ERR, "recv (state0): %m");
  564: 			h->state = 100;
  565: 		}
  566: 		else if(n==0)
  567: 		{
  568: 			syslog(LOG_WARNING, "HTTP Connection closed inexpectedly");
  569: 			h->state = 100;
  570: 		}
  571: 		else
  572: 		{
  573: 			const char * endheaders;
  574: 			/* if 1st arg of realloc() is null,
  575: 			 * realloc behaves the same as malloc() */
  576: 			h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen + 1);
  577: 			memcpy(h->req_buf + h->req_buflen, buf, n);
  578: 			h->req_buflen += n;
  579: 			h->req_buf[h->req_buflen] = '\0';
  580: 			/* search for the string "\r\n\r\n" */
  581: 			endheaders = findendheaders(h->req_buf, h->req_buflen);
  582: 			if(endheaders)
  583: 			{
  584: 				h->req_contentoff = endheaders - h->req_buf + 4;
  585: 				ProcessHttpQuery_upnphttp(h);
  586: 			}
  587: 		}
  588: 		break;
  589: 	case 1:
  590: 		n = recv(h->socket, buf, 2048, 0);
  591: 		if(n<0)
  592: 		{
  593: 			syslog(LOG_ERR, "recv (state1): %m");
  594: 			h->state = 100;
  595: 		}
  596: 		else if(n==0)
  597: 		{
  598: 			syslog(LOG_WARNING, "HTTP Connection closed inexpectedly");
  599: 			h->state = 100;
  600: 		}
  601: 		else
  602: 		{
  603: 			/*fwrite(buf, 1, n, stdout);*/	/* debug */
  604: 			h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen);
  605: 			memcpy(h->req_buf + h->req_buflen, buf, n);
  606: 			h->req_buflen += n;
  607: 			if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
  608: 			{
  609: 				ProcessHTTPPOST_upnphttp(h);
  610: 			}
  611: 		}
  612: 		break;
  613: 	default:
  614: 		syslog(LOG_WARNING, "Unexpected state: %d", h->state);
  615: 	}
  616: }
  617: 
  618: static const char httpresphead[] =
  619: 	"%s %d %s\r\n"
  620: 	/*"Content-Type: text/xml; charset=\"utf-8\"\r\n"*/
  621: 	"Content-Type: %s\r\n"
  622: 	"Connection: close\r\n"
  623: 	"Content-Length: %d\r\n"
  624: 	"Server: " MINIUPNPD_SERVER_STRING "\r\n"
  625: 	;	/*"\r\n";*/
  626: /*
  627: 		"<?xml version=\"1.0\"?>\n"
  628: 		"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
  629: 		"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
  630: 		"<s:Body>"
  631: 
  632: 		"</s:Body>"
  633: 		"</s:Envelope>";
  634: */
  635: /* with response code and response message
  636:  * also allocate enough memory */
  637: 
  638: void
  639: BuildHeader_upnphttp(struct upnphttp * h, int respcode,
  640:                      const char * respmsg,
  641:                      int bodylen)
  642: {
  643: 	int templen;
  644: 	if(!h->res_buf)
  645: 	{
  646: 		templen = sizeof(httpresphead) + 128 + bodylen;
  647: 		h->res_buf = (char *)malloc(templen);
  648: 		if(!h->res_buf)
  649: 		{
  650: 			syslog(LOG_ERR, "malloc error in BuildHeader_upnphttp()");
  651: 			return;
  652: 		}
  653: 		h->res_buf_alloclen = templen;
  654: 	}
  655: 	h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
  656: 	                         httpresphead, h->HttpVer,
  657: 	                         respcode, respmsg,
  658: 	                         (h->respflags&FLAG_HTML)?"text/html":"text/xml",
  659: 							 bodylen);
  660: 	/* Additional headers */
  661: #ifdef ENABLE_EVENTS
  662: 	if(h->respflags & FLAG_TIMEOUT) {
  663: 		h->res_buflen += snprintf(h->res_buf + h->res_buflen,
  664: 		                          h->res_buf_alloclen - h->res_buflen,
  665: 		                          "Timeout: Second-");
  666: 		if(h->req_Timeout) {
  667: 			h->res_buflen += snprintf(h->res_buf + h->res_buflen,
  668: 			                          h->res_buf_alloclen - h->res_buflen,
  669: 			                          "%d\r\n", h->req_Timeout);
  670: 		} else {
  671: 			h->res_buflen += snprintf(h->res_buf + h->res_buflen,
  672: 			                          h->res_buf_alloclen - h->res_buflen,
  673: 			                          "infinite\r\n");
  674: 		}
  675: 	}
  676: 	if(h->respflags & FLAG_SID) {
  677: 		h->res_buflen += snprintf(h->res_buf + h->res_buflen,
  678: 		                          h->res_buf_alloclen - h->res_buflen,
  679: 		                          "SID: %s\r\n", h->req_SID);
  680: 	}
  681: #endif
  682: 	h->res_buf[h->res_buflen++] = '\r';
  683: 	h->res_buf[h->res_buflen++] = '\n';
  684: 	if(h->res_buf_alloclen < (h->res_buflen + bodylen))
  685: 	{
  686: 		char * tmp;
  687: 		tmp = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
  688: 		if(tmp)
  689: 		{
  690: 			h->res_buf = tmp;
  691: 			h->res_buf_alloclen = h->res_buflen + bodylen;
  692: 		}
  693: 		else
  694: 		{
  695: 			syslog(LOG_ERR, "realloc error in BuildHeader_upnphttp()");
  696: 		}
  697: 	}
  698: }
  699: 
  700: void
  701: BuildResp2_upnphttp(struct upnphttp * h, int respcode,
  702:                     const char * respmsg,
  703:                     const char * body, int bodylen)
  704: {
  705: 	BuildHeader_upnphttp(h, respcode, respmsg, bodylen);
  706: 	if(body)
  707: 		memcpy(h->res_buf + h->res_buflen, body, bodylen);
  708: 	h->res_buflen += bodylen;
  709: }
  710: 
  711: /* responding 200 OK ! */
  712: void
  713: BuildResp_upnphttp(struct upnphttp * h,
  714:                         const char * body, int bodylen)
  715: {
  716: 	BuildResp2_upnphttp(h, 200, "OK", body, bodylen);
  717: }
  718: 
  719: void
  720: SendResp_upnphttp(struct upnphttp * h)
  721: {
  722: 	char * p;
  723: 	ssize_t n;
  724: 	size_t len;
  725: 	p = h->res_buf;
  726: 	len = h->res_buflen;
  727: 	while (len > 0)
  728: 	{
  729: 		n = send(h->socket, p, len, 0);
  730: 		if(n<0)
  731: 		{
  732: 			syslog(LOG_ERR, "send(res_buf): %m");
  733: 		}
  734: 		else if(n == 0)
  735: 		{
  736: 			syslog(LOG_ERR, "send(res_buf): %zd bytes sent (out of %zu)",
  737: 							n, len);
  738: 			break;
  739: 		}
  740: 		else
  741: 		{
  742: 			p += n;
  743: 			len -= n;
  744: 		}
  745: 	}
  746: }
  747: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>