/* * Copyright (c) 2008-2016 Allwinner Technology Co. Ltd. * All rights reserved. * * File : CdxParseUrl.c * Description : ParseUrl * History : * */ #include #include #include #include #include #include #include #ifdef SIZE_MAX #undef SIZE_MAX #endif #define SIZE_MAX ((size_t)-1) void CdxUrlPrintf(CdxUrlT* url) { CDX_LOGD("**********print the url container."); CDX_LOGD("**********ur->url=(%s)", url->url); CDX_LOGD("**********ur->protocol=%s", url->protocol); CDX_LOGD("**********ur->hostname=%s", url->hostname); CDX_LOGD("**********ur->file=%s", url->file); CDX_LOGD("**********ur->port=%u", url->port); CDX_LOGD("**********ur->username=%s", url->username); CDX_LOGD("**********ur->password=%s", url->password); } CdxUrlT* CdxUrlNew(char* url) { int pos1 = 0; int pos2 = 0; int v6addr = 0; int len = 0; int len2 = 0; char *p1 = NULL; char *p2 = NULL; char *p3 = NULL; char *p4 = NULL; int nJump = 3; CdxUrlT* curUrl = NULL; char *pEscName = NULL; if(url == NULL) { CDX_LOGE("url null"); return NULL; } if(strlen(url) >(SIZE_MAX/3 - 1)) { CDX_LOGE("the length of the url is too longer."); goto err_out; } pEscName = malloc(strlen(url)*3+1); if(pEscName == NULL) { CDX_LOGE("malloc memory for pEscName failed."); goto err_out; } // Create the URL container curUrl = malloc(sizeof(CdxUrlT)); if(curUrl == NULL) { CDX_LOGE("malloc memory for curUrl failed."); goto err_out; } //Initialisation of the URL container members memset(curUrl, 0, sizeof(CdxUrlT)); CdxUrlEscapeString(pEscName,url); // Copy the url in the URL container curUrl->url = strdup(pEscName); if(curUrl->url == NULL) { CDX_LOGE("curUrl->url is NULL."); goto err_out; } // extract the protocol p1 = strstr(pEscName, "://"); if(p1 == NULL) { // Check for a special case: "sip:" (without "//"): if(strstr(pEscName, "sip:") == pEscName) { p1 = (char *)&url[3]; // points to ':' nJump = 1; } else { CDX_LOGE("the url (%s) is not a URL.", pEscName); goto err_out; } } pos1 = p1-pEscName; curUrl->protocol = malloc(pos1+1); if(curUrl->protocol == NULL) { CDX_LOGE("curUrl->protocol is NULL."); goto err_out; } strncpy(curUrl->protocol, pEscName, pos1); curUrl->protocol[pos1] = '\0'; // jump the "://" p1 += nJump; pos1 += nJump; //check if a username:password is given p2 = strstr(p1, "@"); p3 = strstr(p1, "/"); if(p3!=NULL && p3username = malloc(len+1); if(curUrl->username == NULL ) { CDX_LOGE("curUrl->username is faile."); goto err_out; } strncpy(curUrl->username, p1, len); curUrl->username[len] = '\0'; p3 = strstr(p1, ":"); if(p3!=NULL && p3username[p3-p1]='\0'; curUrl->password = malloc(len2+1); if(curUrl->password == NULL) { CDX_LOGE("curUrl->password is failed."); goto err_out; } strncpy(curUrl->password, p3+1, len2); curUrl->password[len2]='\0'; } p1 = p2+1; pos1 = p1-pEscName; } // before looking for a port number check if we have an IPv6 type numeric address // in IPv6 URL the numeric address should be inside square braces. char *sLeft = "["; char *sRight = "]"; char *fSlash = "/"; p2 = strstr(p1, sLeft); p3 = strstr(p1, sRight); p4 = strstr(p1, fSlash); if((p2 != NULL) && (p3 != NULL) && (p2 < p3) && (!p4 || (p4 > p3))) { // we have an IPv6 numeric address p1++; pos1++; p2 = p3; v6addr = 1; } else { p2 = p1; } // look if the port is given p2 = strstr(p2, ":"); // If the : is after the first / it isn't the port p3 = strstr(p1, "/"); if(p3 && p3 - p2 < 0) { p2 = NULL; } if(p2==NULL) { // No port is given, Look if a path is given if(p3==NULL) { // No path/filename, So we have an URL like http://www.hostname.com pos2 = strlen(pEscName); } else { // We have an URL like http://www.hostname.com/file.txt pos2 = p3-pEscName; } } else { // We have an URL beginning like http://www.hostname.com:1212, Get the port number curUrl->port = atoi(p2+1); pos2 = p2-pEscName; } if(v6addr) { pos2--; } // copy the hostname in the URL container curUrl->hostname = malloc(pos2-pos1+1); if(curUrl->hostname==NULL) { CDX_LOGE("curUrl->hostname is NULL."); goto err_out; } strncpy(curUrl->hostname, p1, pos2-pos1); curUrl->hostname[pos2-pos1] = '\0'; // Look if a path is given p2 = strstr(p1, "/"); if(p2 != NULL) { //A path/filename is given, check if it's not a trailing '/' if(strlen(p2) > 1) { // copy the path/filename in the URL container curUrl->file = strdup(p2); if(curUrl->file==NULL) { CDX_LOGE("curURL is NULL."); goto err_out; } } } // Check if a filename was given or set, else set it with '/' if(curUrl->file==NULL) { curUrl->file = malloc(2); if(curUrl->file==NULL) { CDX_LOGE("curURL file is NULL."); goto err_out; } strcpy(curUrl->file, "/"); } free(pEscName); pEscName = NULL; return curUrl; err_out: if(pEscName) { free(pEscName); pEscName = NULL; } if(curUrl) { CdxUrlFree(curUrl); } return NULL; } //*******************************************************************************************// /* Replace specific characters in the URL string by an escape sequence */ /* works like strcpy(), but without return argument */ //*******************************************************************************************// void CdxUrlEscapeString(char *pOutbuf, const char *pInbuf) { unsigned char a; int i = 0; int j = 0; int len = 0; char *pTmp = NULL; char *in = NULL; char *pUnesc = NULL; len = strlen(pInbuf); // Look if we have an ip6 address, if so skip it there is no need to escape anything in there. pTmp = strstr(pInbuf,"://["); if(pTmp) { pTmp = strchr(pTmp + 4, ']'); if(pTmp && ('/' == pTmp[1] || ':' == pTmp[1] || '\0' == pTmp[1])) { i = pTmp + 1 - pInbuf; strncpy(pOutbuf, pInbuf, i); pOutbuf += i; pTmp = NULL; } } pTmp = NULL; while(i < len) { // look for the next char that must be kept for(j=i; j='0' && c1<='9') || (c1>='A' && c1<='F')) && if ((c1>='0' && c1<='7') && ((c2>='0' && c2<='9') || (c2>='A' && c2<='F'))) { if (c1>='0' && c1<='9') { c1-='0'; } else { c1-='A'-10; } if(c2>='0' && c2<='9') { c2-='0'; } else { c2-='A'-10; } c = (c1<<4) + c2; i= i+2; //only skip next 2 chars if valid esc } } *pOutbuf++ = c; } *pOutbuf++='\0'; //add nullterm to string } //*******************************************************************************************// //*******************************************************************************************// void CdxUrlEscapeStringPart(char *pOutbuf, const char *pInbuf) { int i = 0; int len = 0; unsigned char c, c_1, c_2; len=strlen(pInbuf); for(i=0; i= 'A' && c <= 'Z') ||(c >= 'a' && c <= 'z') ||(c >= '0' && c <= '9') ||(c >= 0x7f)) if((c >= 'A' && c <= 'Z') ||(c >= 'a' && c <= 'z') ||(c >= '0' && c <= '9')) { *pOutbuf++ = c; } else if(c == '%' && ((c_1 >= '0' && c_1 <= '9') || (c_1 >= 'A' && c_1 <= 'F')) && ((c_2 >= '0' && c_2 <= '9') || (c_2 >= 'A' && c_2 <= 'F'))) { // check if part of an escape sequence already *pOutbuf++ = c; // dont escape again error as this should not happen // against RFC 2396 to escape a string twice } else { // all others will be escaped c_1 = ((c & 0xf0) >> 4); c_2 = (c & 0x0f); if(c_1 < 10) { c_1 += '0'; } else { c_1 += 'A'-10; } if(c_2 < 10) { c_2 += '0'; } else { c_2 += 'A'-10; } *pOutbuf++ = '%'; *pOutbuf++ = c_1; *pOutbuf++ = c_2; } } *pOutbuf++ = '\0'; } void CdxUrlFree(CdxUrlT* curUrl) { if(curUrl == NULL) { return; } if(curUrl->url) { free(curUrl->url); } if(curUrl->protocol) { free(curUrl->protocol); } if(curUrl->hostname) { free(curUrl->hostname); } if(curUrl->file) { free(curUrl->file); } if(curUrl->username) { free(curUrl->username); } if(curUrl->password) { free(curUrl->password); } if(curUrl->noauth_url) { free(curUrl->noauth_url); } free(curUrl); } CdxUrlT* CdxCheck4Proxies(CdxUrlT *url) { int len = 0; CdxUrlT *urlOut = NULL; char *proxy = NULL; char *newUrl = NULL; CdxUrlT *tmpUrl = NULL; CdxUrlT *proxyUrl = NULL; if(url == NULL) { return NULL; } urlOut = CdxUrlNew(url->url); if(!strcasecmp(url->protocol, "http_proxy")) { CDX_LOGI("Using HTTP proxy: http://%s:%d\n", url->hostname, url->port); return urlOut; } // Check if the http_proxy environment variable is set. if(!strcasecmp(url->protocol, "http")) { proxy = getenv("http_proxy"); if(proxy != NULL) { // We got a proxy, build the URL to use it proxyUrl = CdxUrlNew(proxy); if(proxyUrl == NULL) { CDX_LOGI("proxy_url is NULL."); return urlOut; } #ifdef HAVE_AF_INET6 if(network_ipv4_only_proxy && (gethostbyname(url->hostname)==NULL)) { CdxUrlFree(proxyUrl); return urlOut; } #endif // 20 = http_proxy:// + port len = strlen(proxyUrl->hostname) + strlen(url->url) + 20; newUrl = malloc(len+1); if (newUrl == NULL) { CdxUrlFree(proxyUrl); return urlOut; } sprintf(newUrl, "http_proxy://%s:%d/%s", proxyUrl->hostname, proxyUrl->port, url->url); tmpUrl = CdxUrlNew(newUrl); if(tmpUrl == NULL) { free(newUrl); newUrl = NULL; CdxUrlFree(proxyUrl); return urlOut; } CdxUrlFree(urlOut); urlOut = tmpUrl; free(newUrl); newUrl = NULL; CdxUrlFree(proxyUrl); } } return urlOut; } #if 0 char *aw_mp_asprintf(char *fmt, ...) { char *p = NULL; va_list va; int len; va_start(va, fmt); len = vsnprintf(NULL, 0, fmt, va); va_end(va); if(len < 0) { goto end; } p = malloc(len + 1); if(!p) { goto end; } va_start(va, fmt); len = vsnprintf(p, len + 1, fmt, va); va_end(va); if(len < 0) { free(p); p = NULL; } end: return p; } char *CdxGetNoauthUrl(CdxUrlT *url) { if(url->port) { return aw_mp_asprintf("%s://%s:%d%s", url->protocol, url->hostname, url->port, url->file); } else { return aw_mp_asprintf("%s://%s%s", url->protocol, url->hostname, url->file); } } #endif CdxUrlT *CdxUrlRedirect(CdxUrlT **url, char *pRedir) { CdxUrlT *u = *url; CdxUrlT *res; if(!strchr(pRedir, '/') || *pRedir == '/') { char *pTmp; char *newurl = malloc(strlen(u->url) + strlen(pRedir) + 1); strcpy(newurl, u->url); if (*pRedir == '/') { pRedir++; pTmp = strstr(newurl, "://"); if(pTmp) { pTmp = strchr(pTmp + 3, '/'); } } else { pTmp = strrchr(newurl, '/'); } if(pTmp) { pTmp[1] = 0; } strcat(newurl, pRedir); res = CdxUrlNew(newurl); free(newurl); } else { res = CdxUrlNew(pRedir); } CdxUrlFree(u); *url = res; return res; }