667 lines
16 KiB
C
Executable File
667 lines
16 KiB
C
Executable File
/*
|
|
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
|
|
* All rights reserved.
|
|
*
|
|
* File : CdxParseUrl.c
|
|
* Description : ParseUrl
|
|
* History :
|
|
*
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <CdxUrl.h>
|
|
#include <ctype.h>
|
|
#include <CdxLog.h>
|
|
|
|
#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 && p3<p2)
|
|
{
|
|
// it isn't really a username but rather a part of the path
|
|
p2 = NULL;
|
|
}
|
|
|
|
if(p2 != NULL)
|
|
{
|
|
// We got something, at least a username...
|
|
len = p2-p1;
|
|
curUrl->username = 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 && p3<p2)
|
|
{
|
|
// We also have a password
|
|
len2 = p2-p3-1;
|
|
curUrl->username[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<len; j++)
|
|
{
|
|
a = pInbuf[j];
|
|
if(a=='-' || a=='_' || a=='.' || a=='!' || // mark characters, see RFC 2396.
|
|
a=='~' || a=='*' || a=='\'' || a=='(' ||
|
|
a==')' || a==';' || a=='/' || a=='?' ||
|
|
a==':' || a=='@' || a=='&' || a=='=' ||
|
|
a=='+' || a=='$' || a==',' || a=='[' ||
|
|
a==']')
|
|
break;
|
|
}
|
|
// we are on a reserved char, write it out
|
|
if(j == i)
|
|
{
|
|
*pOutbuf++ = a;
|
|
i++;
|
|
continue;
|
|
}
|
|
// we found one, take that part of the string
|
|
if(j < len)
|
|
{
|
|
if(!pTmp)
|
|
{
|
|
pTmp = malloc(len+1);
|
|
}
|
|
strncpy(pTmp,pInbuf+i,j-i);
|
|
pTmp[j-i] = '\0';
|
|
in = pTmp;
|
|
}
|
|
else // take the rest of the string
|
|
{
|
|
in = (char*)pInbuf+i;
|
|
}
|
|
|
|
if(!pUnesc)
|
|
{
|
|
pUnesc = malloc(len+1);
|
|
}
|
|
// unescape first to avoid escaping escape
|
|
//CdxUrlUnescapeString(pUnesc, in);
|
|
// then escape, including mark and other reserved char that can come from escape sequences
|
|
CdxUrlEscapeStringPart(pOutbuf, in);
|
|
pOutbuf += strlen(pOutbuf);
|
|
i += strlen(in);
|
|
}
|
|
*pOutbuf = '\0';
|
|
|
|
if(pTmp)
|
|
{
|
|
free(pTmp);
|
|
pTmp = NULL;
|
|
}
|
|
if(pUnesc)
|
|
{
|
|
free(pUnesc);
|
|
pUnesc = NULL;
|
|
}
|
|
}
|
|
|
|
//*******************************************************************************************//
|
|
/* Replace escape sequences in an URL (or a part of an URL) */
|
|
/* works like strcpy(), but without return argument */
|
|
//*******************************************************************************************//
|
|
|
|
void CdxUrlUnescapeString(char *pOutbuf, const char *pInbuf)
|
|
{
|
|
int i = 0;
|
|
int len = 0;
|
|
unsigned char c,c1,c2;
|
|
|
|
len = strlen(pInbuf);
|
|
for (i=0;i<len;i++)
|
|
{
|
|
c = pInbuf[i];
|
|
if ((c == '%') && (i < len-2)) //must have 2 more chars
|
|
{
|
|
c1 = toupper(pInbuf[i+1]); // we need uppercase characters
|
|
c2 = toupper(pInbuf[i+2]);
|
|
//if (((c1>='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<len; i++)
|
|
{
|
|
c = pInbuf[i];
|
|
if (('%' == c) && (i<len-2) )
|
|
{
|
|
//need 2 more characters
|
|
c_1 = toupper(pInbuf[i+1]);
|
|
c_2 = toupper(pInbuf[i+2]); // need uppercase chars
|
|
}
|
|
else
|
|
{
|
|
c_1 = 129;
|
|
c_2 = 129; //not escape chars
|
|
}
|
|
|
|
//if((c >= '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;
|
|
}
|