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); }
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"); }