Ejemplo n.º 1
0
static void cg_http_server_clientthread(CgThread *thread)
{
	CgHttpServerClientData *clientData;
	CgHttpServer *httpServer;
	CgSocket *clientSock;
	void *httpServerUserData;
	CgHttpRequest *httpReq;
	char *version = NULL;

	cg_log_debug_l4("Entering...\n");

	clientData = (CgHttpServerClientData *)cg_thread_getuserdata(thread);
	httpServer = clientData->httpServer;
	clientSock = clientData->clientSock;
	httpServerUserData = cg_http_server_getuserdata(httpServer);

	httpReq = cg_http_request_new();
	cg_http_request_setsocket(httpReq, clientSock);

	/**** Thanks for Makela Aapo (10/31/05) ****/
	while (cg_http_request_read(httpReq, clientSock) == TRUE && cg_thread_isrunnable(thread) == TRUE) {
		/* Check some validity of the request */
		version = cg_http_request_getversion(httpReq);
		if (cg_strcmp(version, CG_HTTP_VER11) == 0)
		{
			/* According to HTTP/1.1 spec, we must not tolerate
			   HTTP/1.1 request without HOST-header */
			if (cg_http_request_gethost(httpReq) == NULL)
			{
				cg_http_request_postbadrequest(httpReq);
				continue;
			}
		}

		if (httpServer->listener != NULL) {
            cg_http_request_setuserdata(httpReq, httpServerUserData);
			httpServer->listener(httpReq);
		}

		/* Close connection according to HTTP version and headers */
		if (cg_strcmp(version, CG_HTTP_VER10) == 0)
		{
			/* Terminate connection after HTTP/1.0 request */
			break;
		}

		/* We are having HTTP/1.1 or better => terminate, if requested */
		if (cg_http_request_iskeepaliveconnection(httpReq) == FALSE)
		{
			break;
		}
	}

	cg_log_debug_s("Dropping HTTP client\n");
	cg_http_request_delete(httpReq);

	cg_socket_close(clientSock);
	cg_socket_delete(clientSock);

	cg_http_server_clientdata_delete(clientData);
	cg_thread_setuserdata(thread, NULL);

    // This code frequently crashes. mutex lock referencing free'd memory.
	cg_http_server_lock(httpServer);
	cg_thread_remove(thread);
	cg_http_server_unlock(httpServer);

	cg_log_debug_l4("Leaving...\n");

	cg_thread_delete(thread);
}
Ejemplo n.º 2
0
void cg_upnp_dms_youtube_http_listener(CgHttpRequest *httpReq)
{
	CgUpnpMediaServer *dms;
	CgUpnpDevice *dev;
	char *httpURI;
	int contentMD5Idx;
	char *contentMd5;
	CgHttpResponse *httpRes;
	CgSocket *sock;
	char chunkedChar[32];
	BOOL isHeadRequest;
	struct stat fileStat;
	off_t fileSize;
	FILE *fp;
	char readBuf[CG_FILE_READ_CHUNK_SIZE];
	off_t nRead;
	off_t nReadCnt;
	off_t nWroteCnt;
	char contentFile[CG_MD5_STRING_BUF_SIZE+8];

	dev = (CgUpnpDevice *)cg_http_request_getuserdata(httpReq);
	if (!dev) {
		cg_http_request_postbadrequest(httpReq);
		return;
	}

	dms = (CgUpnpMediaServer *)cg_upnp_device_getuserdata(dev);
	if (!dms) {
		cg_http_request_postbadrequest(httpReq);
		return;
	}

	httpURI = cg_http_request_geturi(httpReq);
	if (cg_strlen(httpURI) <= 0) {
		cg_http_request_postbadrequest(httpReq);
		return;
	}

	if (cg_strstr(httpURI, CG_UPNP_MEDIA_YOUTUBE_RESURL_PATH) < 0) {
		cg_upnp_device_httprequestrecieved(httpReq);
		return;
	}

	contentMD5Idx = cg_strrchr(httpURI, "/", 1);
	
	if (contentMD5Idx < 0) {
		cg_http_request_postbadrequest(httpReq);
		return;
	}
	
	contentMd5 = httpURI + contentMD5Idx + 1;
	cg_strcpy(contentFile, contentMd5);
	cg_strcat(contentFile, "." CG_UPNP_MEDIA_YOUTUBE_TRANSCODE_FILEEXT);

	cg_upnp_dms_lock(dms);

	isHeadRequest = cg_http_request_isheadrequest(httpReq);
	
	httpRes = cg_http_response_new();
#if defined(CG_USE_CHUNKED_STREAM)
	cg_http_response_setversion(httpRes, CG_HTTP_VER11);
#else
	cg_http_response_setversion(httpRes, CG_HTTP_VER10);
#endif
	cg_http_response_setstatuscode(httpRes, CG_HTTP_STATUS_OK);
	cg_http_response_setcontenttype(httpRes, CG_UPNP_MEDIA_YOUTUBE_CONTENT_MIMETYPE);
	
	sock = cg_http_request_getsocket(httpReq);
	cg_socket_settimeout(sock, 0);

	fileSize = 0;
	if (stat(contentFile, &fileStat) == 0)
		fileSize = fileStat.st_size;
#if defined(CG_USE_CHUNKED_STREAM)
	cg_http_packet_setheadervalue((CgHttpPacket*)httpRes, "Transfer-Encoding", "chunked");
#else
	cg_http_response_setcontentlength(httpRes, fileSize);
#endif
	cg_http_request_postresponse(httpReq, httpRes);

	if (0 < fileSize) {		
		nReadCnt = 0;
		nWroteCnt = 0;
		fp = fopen(contentFile, "rb");
		if (fp) {
			nRead = fread(readBuf, sizeof(char), CG_FILE_READ_CHUNK_SIZE, fp);
			while (nReadCnt < fileSize && 0 < nRead) {
				nReadCnt += nRead;
#if defined(CG_USE_CHUNKED_STREAM)
				sprintf(chunkedChar, "%x%s", nRead, CG_HTTP_CRLF);
				cg_socket_write(sock, chunkedChar, cg_strlen(chunkedChar));
#endif
				nWroteCnt += cg_socket_write(sock, readBuf, nRead);
#if defined(CG_USE_CHUNKED_STREAM)
				cg_socket_write(sock, CG_HTTP_CRLF, sizeof(CG_HTTP_CRLF)-1);
#endif
				nRead = fread(readBuf, sizeof(char), CG_FILE_READ_CHUNK_SIZE, fp);
			}
			fclose(fp);
		}
	}
	
#if defined(CG_USE_CHUNKED_STREAM)
	sprintf(chunkedChar, "%x%s", 0, CG_HTTP_CRLF);
	cg_socket_write(sock, chunkedChar, cg_strlen(chunkedChar));
#endif
	
	cg_socket_close(sock);
	cg_http_response_delete(httpRes);

	cg_upnp_dms_unlock(dms);
}
/**
 * The function that calls all HTTP listener callback functions. Do not call
 * this from applications.
 *
 * @param httpReq The received HTTP request
 */
void cg_upnp_controlpoint_httprequestreceived(CgHttpRequest *httpReq)
{
	CgUpnpControlPoint *ctrlPoint = NULL;
	CgUpnpNotifyRequest *notifyReq = NULL;
	CgUpnpPropertyList *propList = NULL;
	CgUpnpProperty *prop = NULL;
	CgUpnpEventListenerList *eventListeners = NULL;
	const char *sid = NULL;
	long seq = 0;
	long timeout = 0;
	CgUpnpDevice *dev = NULL;
	CgUpnpService *service = NULL;
	int notifyListeners = 0;
	
	cg_log_debug_l4("Entering...\n");

	ctrlPoint = (CgUpnpControlPoint *)cg_http_request_getuserdata(httpReq);

	cg_upnp_controlpoint_lock(ctrlPoint);

#if !defined(CG_UPNP_NOUSE_SUBSCRIPTION)
	if (cg_http_request_isnotifyrequest(httpReq) == TRUE) {	
		notifyReq = cg_upnp_event_notify_request_new();
		cg_upnp_event_notify_request_sethttprequest(notifyReq, httpReq);

		/* Get service according to SID */
		sid = cg_upnp_event_notify_request_getsid(notifyReq);
		
		for (dev = cg_upnp_controlpoint_getdevices(ctrlPoint); 
		     dev != NULL;
		     dev = cg_upnp_device_next(dev))
		{
			service = cg_upnp_device_getservicebysid(dev, sid);
			if (service != NULL) break;
		}

		if (service != NULL) {
			/* We found a service */
			seq = cg_upnp_event_notify_request_getseq(notifyReq);
			
			/* Check that event key = previous + 1 */
			if (seq != 0 && seq != cg_upnp_service_geteventkey(service) + 1)
			{
				/* The sequence does not match, unsubscribe and subscribe */
				timeout = cg_upnp_service_getsubscriptiontimeout(service);
				cg_upnp_controlpoint_unsubscribe(ctrlPoint, service);
				cg_upnp_controlpoint_subscribe(ctrlPoint, service, timeout);
			} else {
				/* Wrap seq, so that assertion is true next time */
				if (seq == CG_UPNP_EVENT_MAX_SEQ) seq = 0;
				
				/* Set event key */
				cg_upnp_service_seteventkey(service, seq);
				
				notifyListeners = 1;
				propList = cg_upnp_event_notify_request_getpropertylist(notifyReq); 
				for (prop=cg_upnp_propertylist_gets(propList); 
				     prop != NULL; 
				     prop = cg_upnp_property_next(prop)) 
				{
					/* Update the service's state table from the event */
					cg_upnp_controlpoint_updatestatetablefromproperty(service, prop);
				}
			}
		}
		eventListeners = cg_upnp_controlpoint_geteventlisteners(ctrlPoint);
		cg_upnp_controlpoint_unlock(ctrlPoint);

		if (notifyListeners && propList != NULL) 
		{
			/* Notify listeners out of control point lock */
			for (prop=cg_upnp_propertylist_gets(propList); 
			     prop != NULL; 
			     prop = cg_upnp_property_next(prop)) 
			{
				cg_upnp_eventlistenerlist_notify(eventListeners, prop);
			}
		}

		cg_upnp_event_notify_request_delete(notifyReq);
		cg_http_request_postokrequest(httpReq);
		
		return;
	}
#endif
	
	cg_upnp_controlpoint_unlock(ctrlPoint);
	cg_http_request_postbadrequest(httpReq);

	cg_log_debug_l4("Leaving...\n");
}