char *cg_upnp_ssdprequest_tostring(CgUpnpSSDPRequest *ssdpReq, CgString *ssdpMsg) { CgHttpHeader *header; const char *name; const char *value; cg_log_debug_l4("Entering...\n"); cg_string_addvalue(ssdpMsg, cg_http_request_getmethod(ssdpReq)); cg_string_addvalue(ssdpMsg, CG_HTTP_SP); cg_string_addvalue(ssdpMsg, cg_http_request_geturi(ssdpReq)); cg_string_addvalue(ssdpMsg, CG_HTTP_SP); cg_string_addvalue(ssdpMsg, cg_http_request_getversion(ssdpReq)); cg_string_addvalue(ssdpMsg, CG_HTTP_CRLF); for (header = cg_http_packet_getheaders((CgHttpPacket *)ssdpReq); header != NULL; header = cg_http_header_next(header)) { name = cg_http_header_getname(header); value = cg_http_header_getvalue(header); cg_string_addvalue(ssdpMsg, name); cg_string_addvalue(ssdpMsg, CG_HTTP_COLON); cg_string_addvalue(ssdpMsg, CG_HTTP_SP); cg_string_addvalue(ssdpMsg, value); cg_string_addvalue(ssdpMsg, CG_HTTP_CRLF); } cg_string_addvalue(ssdpMsg, CG_HTTP_CRLF); return cg_string_getvalue(ssdpMsg); cg_log_debug_l4("Leaving...\n"); }
void cg_http_request_copy(CgHttpRequest *destHttpReq, CgHttpRequest *srcHttpReq) { cg_log_debug_l4("Entering...\n"); cg_http_request_setmethod(destHttpReq, cg_http_request_getmethod(srcHttpReq)); cg_http_request_seturi(destHttpReq, cg_http_request_geturi(srcHttpReq)); cg_http_request_setversion(destHttpReq, cg_http_request_getversion(srcHttpReq)); cg_http_packet_copy((CgHttpPacket *)destHttpReq, (CgHttpPacket *)srcHttpReq); cg_log_debug_l4("Leaving...\n"); }
void cg_http_request_print(CgHttpRequest *httpReq) { cg_log_debug_l4("Entering...\n"); cg_log_debug_s("%s %s %s\n", cg_http_request_getmethod(httpReq), cg_http_request_geturi(httpReq), cg_http_request_getversion(httpReq)); cg_http_packet_print((CgHttpPacket *)httpReq); cg_log_debug_l4("Leaving...\n"); }
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); }
void upnp_clock_device_httprequestrecieved(CgHttpRequest *httpReq) { CgTime currTime; CgUpnpDevice *dev; char *uri; char content[2048]; char sysTimeStr[SYSTEM_TIME_BUF_LEN]; char serverName[CG_UPNP_SEVERNAME_MAXLEN]; CgHttpResponse *httpRes; BOOL postRet; dev = (CgUpnpDevice *)cg_http_request_getuserdata(httpReq); uri = cg_http_request_geturi(httpReq); if (strcmp(uri, "/presentation") != 0) { cg_upnp_device_httprequestrecieved(httpReq); return; } currTime = cg_getcurrentsystemtime(); #if defined(HAVE_SNPRINTF) snprintf(content, sizeof(content), #else sprintf(content, #endif "<HTML>" "<HEAD>" "<TITLE>UPnP Clock Sample</TITLE>" "</HEAD>" "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"1; URL=/presentation\">" "<BODY><CENTER>" "<H1>UPnP Clock Sample</H1>" "<TABLE border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" "<TR>" "<TD style=\"width: 50px; height: 50px; background-color: rgb(176, 176, 176);\"></TD>" "<TD style=\"background-color: rgb(176, 176, 176);\"></TD>" "<TD style=\"width: 50px; height: 50px; background-color: rgb(176, 176, 176);\"></TD>" "</TR>" "<TR>" "<TD style=\"height: 50px; background-color: rgb(176, 176, 176);\"></TD>" "<TD style=\"height: 50px; background-color: rgb(221, 236, 245);\" align=\"center\"><H1>" "%s" "</H1></TD>" "<TD style=\"height: 50px; background-color: rgb(176, 176, 176);\"></TD>" "</TR>" "<TR>" "<TD style=\"height: 50px; background-color: rgb(176, 176, 176);\"></TD>" "<TD style=\"height: 50px; background-color: rgb(221, 236, 245);\" align=\"center\"><H3>" "Server : %s" "</H3></TD>" "<TD style=\"height: 30px; background-color: rgb(176, 176, 176);\"></TD>" "</TR>" "<TR>" "<TD style=\"width: 30px; height: 50px; background-color: rgb(176, 176, 176);\"></TD>" "<TD style=\"background-color: rgb(176, 176, 176);\"></TD>" "<TD style=\"width: 30px; height: 50px; background-color: rgb(176, 176, 176);\"></TD>" "</TR>" "</TABLE>" "<CENTER></BODY>" "</HTML>", GetSystemTimeString(currTime, sysTimeStr), cg_upnp_getservername(serverName, sizeof(serverName))); httpRes = cg_http_response_new(); cg_http_response_setstatuscode(httpRes, CG_HTTP_STATUS_OK); cg_http_response_setcontent(httpRes, content); cg_http_response_setcontenttype(httpRes, "text/html"); cg_http_response_setcontentlength(httpRes, strlen(content)); postRet = cg_http_request_postresponse(httpReq, httpRes); cg_http_response_delete(httpRes); }
BOOL cg_http_request_read(CgHttpRequest *httpReq, CgSocket *sock) { char lineBuf[CG_HTTP_READLINE_BUFSIZE]; CgStringTokenizer *strTok; int readLen; CgNetURI *uri = NULL; BOOL failed = FALSE; cg_log_debug_l4("Entering...\n"); cg_http_request_clear(httpReq); /* If first character(s) is \n or \r\n we ignore it(them) and read second line. */ do { readLen = cg_socket_readline(sock, lineBuf, sizeof(lineBuf)); } while (readLen >= 1 && readLen <=2); if (readLen <= 0) return FALSE; strTok = cg_string_tokenizer_new(lineBuf, CG_HTTP_STATUSLINE_DELIM); if (cg_string_tokenizer_hasmoretoken(strTok) == TRUE) cg_http_request_setmethod(httpReq, cg_string_tokenizer_nexttoken(strTok)); else failed = TRUE; if (cg_string_tokenizer_hasmoretoken(strTok) == TRUE) cg_http_request_seturi(httpReq, cg_string_tokenizer_nexttoken(strTok)); else failed = TRUE; if (cg_string_tokenizer_hasmoretoken(strTok) == TRUE) cg_http_request_setversion(httpReq, cg_string_tokenizer_nexttoken(strTok)); else failed = TRUE; cg_string_tokenizer_delete(strTok); if (failed == TRUE) return FALSE; /* We could do some further validation for the HTTP-request? */ /* Change URI to be relative (absolute not needed anymore) */ uri = cg_net_uri_new(); if (uri != NULL) { cg_net_uri_set(uri, cg_http_request_geturi(httpReq)); if (cg_net_uri_isabsolute(uri) == TRUE && cg_net_uri_getrequest(uri) != NULL) { cg_http_request_seturi(httpReq, cg_net_uri_getrequest(uri)); } cg_net_uri_delete(uri); uri = NULL; } /* Read headers */ cg_http_packet_clear((CgHttpPacket *)httpReq); cg_http_packet_read_headers((CgHttpPacket *)httpReq, sock, lineBuf, sizeof(lineBuf)); /* HTTP-request must have Content-Length or Transfer-Encoding header in order to have body */ if (cg_http_packet_hasheader((CgHttpPacket *)httpReq, CG_HTTP_CONTENT_LENGTH) || cg_http_packet_hasheader((CgHttpPacket *)httpReq, CG_HTTP_TRANSFER_ENCODING)) cg_http_packet_read_body((CgHttpPacket *)httpReq, sock, lineBuf, sizeof(lineBuf)); cg_log_debug_l4("Leaving...\n"); return TRUE; }
CgHttpResponse *cg_http_request_post(CgHttpRequest *httpReq, char *ipaddr, int port) { CgHttpResponse *httpRes; BOOL newCurl = FALSE; CURL *curl; CgHttpHeader *reqHeader; struct curl_slist *curlHeaderList; CgString *headerStr; CURLcode res; char *uri, *method; char url[CG_NET_URI_MAXLEN]; long retcode; #ifdef CG_SHOW_TIMINGS struct timeval start_time, end_time, elapsed_time; #endif cg_log_debug_l4("Entering...\n"); #ifdef CG_SHOW_TIMINGS gettimeofday(&start_time, NULL); #endif httpRes = httpReq->httpRes; /* Clear the response data because new data will not * overwrite it, but it is appended to the end */ cg_string_clear(httpRes->content); cg_log_debug_s("Posting HTTP request (Curl)\n"); cg_http_request_print(httpReq); cg_http_persistentconnection_lock(); #ifdef CG_HTTP_USE_PERSISTENT_CONNECTIONS cg_log_debug_s("Looking for persistent connection to %s, port %d\n", ipaddr, port); curl = (CURL*)cg_http_persistentconnection_get(ipaddr, port); if (curl == NULL) { cg_log_debug_s("Persistent connection not found...\n"); #endif curl = curl_easy_init(); if (curl == NULL) { cg_http_persistentconnection_unlock(); return httpReq->httpRes; } #ifdef CG_HTTP_USE_PERSISTENT_CONNECTIONS newCurl = TRUE; } #endif method = cg_http_request_getmethod(httpReq); uri = cg_http_request_geturi(httpReq); /**** method ****/ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method); /**** url ****/ if (uri && cg_strstr(uri, CG_NET_URI_PROTOCOL_DELIM) > 0) { curl_easy_setopt(curl, CURLOPT_URL, uri); } else { cg_net_gethosturl(ipaddr, port, uri, url, sizeof(url)); curl_easy_setopt(curl, CURLOPT_URL, url); cg_log_debug_s("\n\nCURL: %s\n\n", url); } /**** header ****/ curlHeaderList = NULL; headerStr = cg_string_new(); for (reqHeader = cg_http_request_getheaders(httpReq); reqHeader; reqHeader = cg_http_header_next(reqHeader)) { cg_string_setvalue(headerStr, cg_http_header_getname(reqHeader)); if (cg_string_addvalue(headerStr, CG_HTTP_COLON CG_HTTP_SP) && cg_string_addvalue(headerStr, cg_http_header_getvalue(reqHeader))) curlHeaderList = curl_slist_append(curlHeaderList, cg_string_getvalue(headerStr)); } cg_string_delete(headerStr); /* Disable Expect header because it causes IOP issues */ curlHeaderList = curl_slist_append(curlHeaderList, "Expect:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curlHeaderList); /**** content ****/ /*if (cg_http_request_ispostrequest(httpReq) == TRUE) {*/ if (cg_http_request_getcontentlength(httpReq) > 0) { curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cg_http_request_getcontent(httpReq)); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, cg_http_request_getcontentlength(httpReq)); } else { curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0); } /* This has to be enabled for progress callback to be called */ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE); /* Used for checking stack state during curl easy perform */ curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, cg_http_request_progress_callback); /**** response header callback ****/ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, cg_http_request_header_callback); curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)httpRes); /**** response content callback ****/ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cg_http_request_content_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)httpRes); /**** useragent ****/ curl_easy_setopt(curl, CURLOPT_USERAGENT, cg_http_request_getuseragent(httpReq) ); /**** Prohibit curl from using signals ****/ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); /**** Set the connection timeout so we don't wait forever ****/ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, CG_HTTP_CURL_CONNECTTIMEOUT); curl_easy_setopt(curl, CURLOPT_TIMEOUT, CG_HTTP_CONN_TIMEOUT); #ifdef CG_SHOW_TIMINGS cg_log_debug_s("\nRequest: %s%s%s\n", method, CG_HTTP_SP, url); #endif /* Get the XML document with CURL */ res = curl_easy_perform(curl); if (res != CURLE_OK) cg_log_debug_s("curl_easy_perform: %s\n", curl_easy_strerror(res)); /* Set the content length, if it wasn't said in the header */ if (cg_http_response_getcontentlength(httpRes) <= 0) { cg_http_response_setcontentlength(httpRes, cg_string_length(httpRes->content)); } curl_slist_free_all(curlHeaderList); curl_easy_getinfo (curl, CURLINFO_HTTP_CODE, &retcode); cg_http_response_setstatuscode(httpRes, retcode); #ifdef CG_SHOW_TIMINGS gettimeofday(&end_time, NULL); timersub(&end_time, &start_time, &elapsed_time); cg_log_debug_s("Getting HTTP-response completed. Elapsed time: " "%ld msec\n", ((elapsed_time.tv_sec*1000) + (elapsed_time.tv_usec/1000))); cg_total_elapsed_time += (elapsed_time.tv_sec*1000000)+ (elapsed_time.tv_usec); #endif #ifdef CG_HTTP_USE_PERSISTENT_CONNECTIONS if (newCurl) { cg_log_debug_s("Putting new connection into cache: %s %d\n", ipaddr, port); cg_http_persistentconnection_put(ipaddr, port, curl); } #else curl_easy_cleanup(curl); #endif cg_http_persistentconnection_unlock(); cg_log_debug_s("Response for HTTP request (Curl)\n"); cg_http_response_print(httpReq->httpRes); return httpReq->httpRes; cg_log_debug_l4("Leaving...\n"); }
CgHttpResponse *cg_http_request_post_main(CgHttpRequest *httpReq, char *ipaddr, int port, BOOL isSecure) { CgSocket *sock; char *method, *uri, *version; #ifdef CG_SHOW_TIMINGS struct timeval start_time, end_time, elapsed_time; #endif CgString *firstLine; cg_log_debug_l4("Entering...\n"); #ifdef CG_SHOW_TIMINGS gettimeofday(&start_time, NULL); #endif cg_http_response_clear(httpReq->httpRes); cg_log_debug_s("(HTTP) Posting:\n"); cg_http_request_print(httpReq); #if defined(CG_USE_OPENSSL) if (isSecure == FALSE) sock = cg_socket_stream_new(); else sock = cg_socket_ssl_new(); #else sock = cg_socket_stream_new(); #endif cg_socket_settimeout(sock, cg_http_request_gettimeout(httpReq)); if (cg_socket_connect(sock, ipaddr, port) == FALSE) { cg_socket_delete(sock); return httpReq->httpRes; } cg_http_request_sethost(httpReq, ipaddr, port); cg_http_packet_setheadervalue((CgHttpPacket*)httpReq, CG_HTTP_USERAGENT, cg_http_request_getuseragent(httpReq)); method = cg_http_request_getmethod(httpReq); uri = cg_http_request_geturi(httpReq); version = cg_http_request_getversion(httpReq); if (method == NULL || uri == NULL || version == NULL) { cg_socket_close(sock); cg_socket_delete(sock); return httpReq->httpRes; } #ifdef CG_SHOW_TIMINGS cg_log_debug_s("\nRequest: %s%s%s:%d%s%s%s\n", method, CG_HTTP_SP, ipaddr, port, uri, CG_HTTP_SP, version); #endif /**** send first line ****/ firstLine = cg_string_new(); cg_string_addvalue(firstLine, method); cg_string_addvalue(firstLine, CG_HTTP_SP); cg_string_addvalue(firstLine, uri); cg_string_addvalue(firstLine, CG_HTTP_SP); cg_string_addvalue(firstLine, version); cg_string_addvalue(firstLine, CG_HTTP_CRLF); cg_socket_write(sock, cg_string_getvalue(firstLine), cg_string_length(firstLine)); cg_string_delete(firstLine); /**** send header and content ****/ cg_http_packet_post((CgHttpPacket *)httpReq, sock); /**** read response ****/ cg_http_response_read(httpReq->httpRes, sock, cg_http_request_isheadrequest(httpReq)); #ifdef CG_SHOW_TIMINGS gettimeofday(&end_time, NULL); timersub(&end_time, &start_time, &elapsed_time); cg_log_debug_s("Getting HTTP-response completed. Elapsed time: " "%ld msec\n", ((elapsed_time.tv_sec*1000) + (elapsed_time.tv_usec/1000))); cg_total_elapsed_time += (elapsed_time.tv_sec*1000000)+ (elapsed_time.tv_usec); #endif cg_socket_close(sock); cg_socket_delete(sock); cg_http_response_print(httpReq->httpRes); cg_log_debug_l4("Leaving...\n"); return httpReq->httpRes; }