
Compiler output is identical before & after this step git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6037 212acab6-be3b-0410-9dea-997c60f758d6
480 lines
9.9 KiB
C++
480 lines
9.9 KiB
C++
/*
|
|
** JNetLib
|
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
** Author: Justin Frankel
|
|
** File: httpget.cpp - JNL HTTP GET implementation
|
|
** License: zlib
|
|
**
|
|
** Reviewed for Unicode Support by Jim Park -- 08/17/2007
|
|
** Note: The functions that work on char's should be explicitely set to use the
|
|
** ANSI versions. Some of the functions like wprintf() are #defined to be
|
|
** the wide-char versions when _UNICODE is defined. So these must be explictly
|
|
** set to use the ANSI versions.
|
|
*/
|
|
|
|
#include "netinc.h"
|
|
#include "util.h"
|
|
#include "httpget.h"
|
|
|
|
void *operator new( unsigned int num_bytes ){return GlobalAlloc(GPTR,num_bytes);}
|
|
void operator delete( void *p ) { if (p) GlobalFree(p); }
|
|
|
|
JNL_HTTPGet::JNL_HTTPGet(JNL_AsyncDNS *dns, int recvbufsize, char *proxy)
|
|
{
|
|
m_recvbufsize=recvbufsize;
|
|
m_dns=dns;
|
|
m_con=NULL;
|
|
m_http_proxylpinfo=0;
|
|
m_http_proxyhost=0;
|
|
m_http_proxyport=0;
|
|
if (proxy && *proxy)
|
|
{
|
|
char *p=(char*)malloc(strlen(proxy)+1);
|
|
if (p)
|
|
{
|
|
char *r=NULL;
|
|
strcpy(p,proxy);
|
|
do_parse_url(p,&m_http_proxyhost,&m_http_proxyport,&r,&m_http_proxylpinfo);
|
|
free(r);
|
|
free(p);
|
|
}
|
|
}
|
|
m_sendheaders=NULL;
|
|
reinit();
|
|
}
|
|
|
|
void JNL_HTTPGet::reinit()
|
|
{
|
|
m_errstr=0;
|
|
m_recvheaders=NULL;
|
|
m_recvheaders_size=0;
|
|
m_http_state=0;
|
|
m_http_port=0;
|
|
m_http_url=0;
|
|
m_reply=0;
|
|
m_http_host=m_http_lpinfo=m_http_request=NULL;
|
|
}
|
|
|
|
void JNL_HTTPGet::deinit()
|
|
{
|
|
delete m_con;
|
|
free(m_recvheaders);
|
|
|
|
free(m_http_url);
|
|
free(m_http_host);
|
|
free(m_http_lpinfo);
|
|
free(m_http_request);
|
|
free(m_errstr);
|
|
free(m_reply);
|
|
reinit();
|
|
}
|
|
|
|
JNL_HTTPGet::~JNL_HTTPGet()
|
|
{
|
|
deinit();
|
|
free(m_sendheaders);
|
|
free(m_http_proxylpinfo);
|
|
free(m_http_proxyhost);
|
|
|
|
}
|
|
|
|
|
|
void JNL_HTTPGet::addheader(char *header)
|
|
{
|
|
//if (strstr(header,"\r") || strstr(header,"\n")) return;
|
|
if (!m_sendheaders)
|
|
{
|
|
m_sendheaders=(char*)malloc(strlen(header)+3);
|
|
if (m_sendheaders)
|
|
{
|
|
strcpy(m_sendheaders,header);
|
|
strcat(m_sendheaders,"\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char *t=(char*)malloc(strlen(header)+strlen(m_sendheaders)+1+2);
|
|
if (t)
|
|
{
|
|
strcpy(t,m_sendheaders);
|
|
strcat(t,header);
|
|
strcat(t,"\r\n");
|
|
free(m_sendheaders);
|
|
m_sendheaders=t;
|
|
}
|
|
}
|
|
}
|
|
|
|
void JNL_HTTPGet::do_encode_mimestr(char *in, char *out)
|
|
{
|
|
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
int shift = 0;
|
|
int accum = 0;
|
|
|
|
while (*in)
|
|
{
|
|
if (*in)
|
|
{
|
|
accum <<= 8;
|
|
shift += 8;
|
|
accum |= *in++;
|
|
}
|
|
while ( shift >= 6 )
|
|
{
|
|
shift -= 6;
|
|
*out++ = alphabet[(accum >> shift) & 0x3F];
|
|
}
|
|
}
|
|
if (shift == 4)
|
|
{
|
|
*out++ = alphabet[(accum & 0xF)<<2];
|
|
*out++='=';
|
|
}
|
|
else if (shift == 2)
|
|
{
|
|
*out++ = alphabet[(accum & 0x3)<<4];
|
|
*out++='=';
|
|
*out++='=';
|
|
}
|
|
|
|
*out++=0;
|
|
}
|
|
|
|
|
|
void JNL_HTTPGet::connect(char *url)
|
|
{
|
|
deinit();
|
|
m_http_url=(char*)malloc(strlen(url)+1);
|
|
strcpy(m_http_url,url);
|
|
do_parse_url(m_http_url,&m_http_host,&m_http_port,&m_http_request, &m_http_lpinfo);
|
|
strcpy(m_http_url,url);
|
|
if (!m_http_host || !m_http_host[0] || !m_http_port)
|
|
{
|
|
m_http_state=-1;
|
|
seterrstr("invalid URL");
|
|
return;
|
|
}
|
|
|
|
int sendbufferlen=0;
|
|
|
|
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
|
{
|
|
sendbufferlen += 4 /* GET */ + strlen(m_http_request) + 9 /* HTTP/1.0 */ + 2;
|
|
}
|
|
else
|
|
{
|
|
sendbufferlen += 4 /* GET */ + strlen(m_http_url) + 9 /* HTTP/1.0 */ + 2;
|
|
if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
|
|
{
|
|
sendbufferlen+=58+strlen(m_http_proxylpinfo)*2; // being safe here
|
|
}
|
|
}
|
|
sendbufferlen += 5 /* Host: */ + strlen(m_http_host) + 2;
|
|
|
|
if (m_http_lpinfo&&m_http_lpinfo[0])
|
|
{
|
|
sendbufferlen+=46+strlen(m_http_lpinfo)*2; // being safe here
|
|
}
|
|
|
|
if (m_sendheaders) sendbufferlen+=strlen(m_sendheaders);
|
|
|
|
char *str=(char*)malloc(sendbufferlen+1024);
|
|
if (!str)
|
|
{
|
|
seterrstr("error allocating memory");
|
|
m_http_state=-1;
|
|
}
|
|
|
|
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
|
{
|
|
wsprintfA(str,"GET %s HTTP/1.0\r\n",m_http_request);
|
|
}
|
|
else
|
|
{
|
|
wsprintfA(str,"GET %s HTTP/1.0\r\n",m_http_url);
|
|
}
|
|
|
|
wsprintfA(str+strlen(str),"Host: %s\r\n",m_http_host);
|
|
|
|
if (m_http_lpinfo&&m_http_lpinfo[0])
|
|
{
|
|
strcat(str,"Authorization: Basic ");
|
|
do_encode_mimestr(m_http_lpinfo,str+strlen(str));
|
|
strcat(str,"\r\n");
|
|
}
|
|
if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
|
|
{
|
|
strcat(str,"Proxy-Authorization: Basic ");
|
|
do_encode_mimestr(m_http_proxylpinfo,str+strlen(str));
|
|
strcat(str,"\r\n");
|
|
}
|
|
|
|
if (m_sendheaders) strcat(str,m_sendheaders);
|
|
strcat(str,"\r\n");
|
|
|
|
int a=m_recvbufsize;
|
|
if (a < 4096) a=4096;
|
|
m_con=new JNL_Connection(m_dns,strlen(str)+4,a);
|
|
if (m_con)
|
|
{
|
|
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
|
{
|
|
m_con->connect(m_http_host,m_http_port);
|
|
}
|
|
else
|
|
{
|
|
m_con->connect(m_http_proxyhost,m_http_proxyport);
|
|
}
|
|
m_con->send_string(str);
|
|
}
|
|
else
|
|
{
|
|
m_http_state=-1;
|
|
seterrstr("could not create connection object");
|
|
}
|
|
free(str);
|
|
|
|
}
|
|
|
|
static int my_strnicmp(char *b1, char *b2, int l)
|
|
{
|
|
while (l-- && *b1 && *b2)
|
|
{
|
|
char bb1=*b1++;
|
|
char bb2=*b2++;
|
|
if (bb1>='a' && bb1 <= 'z') bb1+='A'-'a';
|
|
if (bb2>='a' && bb2 <= 'z') bb2+='A'-'a';
|
|
if (bb1 != bb2) return bb1-bb2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *_strstr(char *i, char *s)
|
|
{
|
|
if (strlen(i)>=strlen(s)) while (i[strlen(s)-1])
|
|
{
|
|
int l=strlen(s)+1;
|
|
char *ii=i;
|
|
char *is=s;
|
|
while (--l>0)
|
|
{
|
|
if (*ii != *is) break;
|
|
ii++;
|
|
is++;
|
|
}
|
|
if (l==0) return i;
|
|
i++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define strstr _strstr
|
|
|
|
void JNL_HTTPGet::do_parse_url(char *url, char **host, int *port, char **req, char **lp)
|
|
{
|
|
char *p,*np;
|
|
free(*host); *host=0;
|
|
free(*req); *req=0;
|
|
free(*lp); *lp=0;
|
|
|
|
if (strstr(url,"://")) np=p=strstr(url,"://")+3;
|
|
else np=p=url;
|
|
while (*np != '/' && *np) np++;
|
|
if (*np)
|
|
{
|
|
*req=(char*)malloc(strlen(np)+1);
|
|
if (*req) strcpy(*req,np);
|
|
*np++=0;
|
|
}
|
|
else
|
|
{
|
|
*req=(char*)malloc(2);
|
|
if (*req) strcpy(*req,"/");
|
|
}
|
|
|
|
np=p;
|
|
while (*np != '@' && *np) np++;
|
|
if (*np)
|
|
{
|
|
*np++=0;
|
|
*lp=(char*)malloc(strlen(p)+1);
|
|
if (*lp) strcpy(*lp,p);
|
|
p=np;
|
|
}
|
|
else
|
|
{
|
|
*lp=(char*)malloc(1);
|
|
if (*lp) strcpy(*lp,"");
|
|
}
|
|
np=p;
|
|
while (*np != ':' && *np) np++;
|
|
if (*np)
|
|
{
|
|
*np++=0;
|
|
*port=my_atoi(np);
|
|
} else *port=80;
|
|
*host=(char*)malloc(strlen(p)+1);
|
|
if (*host) strcpy(*host,p);
|
|
}
|
|
|
|
|
|
char *JNL_HTTPGet::getallheaders()
|
|
{ // double null terminated, null delimited list
|
|
if (m_recvheaders) return m_recvheaders;
|
|
else return "\0\0";
|
|
}
|
|
|
|
char *JNL_HTTPGet::getheader(char *headername)
|
|
{
|
|
char *ret=NULL;
|
|
if (strlen(headername)<1||!m_recvheaders) return NULL;
|
|
char *p=m_recvheaders;
|
|
while (*p)
|
|
{
|
|
if (!my_strnicmp(headername,p,strlen(headername)))
|
|
{
|
|
ret=p+strlen(headername);
|
|
while (*ret == ' ') ret++;
|
|
break;
|
|
}
|
|
p+=strlen(p)+1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int JNL_HTTPGet::run()
|
|
{
|
|
int cnt=0;
|
|
if (m_http_state==-1||!m_con) return -1; // error
|
|
|
|
|
|
run_again:
|
|
static char main_buf[4096];
|
|
char *buf = main_buf;
|
|
m_con->run();
|
|
|
|
if (m_con->get_state()==JNL_Connection::STATE_ERROR)
|
|
{
|
|
seterrstr(m_con->get_errstr());
|
|
return -1;
|
|
}
|
|
if (m_con->get_state()==JNL_Connection::STATE_CLOSED) return 1;
|
|
|
|
if (m_http_state==0) // connected, waiting for reply
|
|
{
|
|
if (m_con->recv_lines_available()>0)
|
|
{
|
|
m_con->recv_line(buf,4095);
|
|
buf[4095]=0;
|
|
m_reply=(char*)malloc(strlen(buf)+1);
|
|
strcpy(m_reply,buf);
|
|
|
|
if (strstr(buf,"200")) m_http_state=2; // proceed to read headers normally
|
|
else if (strstr(buf,"301") || strstr(buf,"302"))
|
|
{
|
|
m_http_state=1; // redirect city
|
|
}
|
|
else
|
|
{
|
|
seterrstr(buf);
|
|
m_http_state=-1;
|
|
return -1;
|
|
}
|
|
cnt=0;
|
|
}
|
|
else if (!cnt++) goto run_again;
|
|
}
|
|
if (m_http_state == 1) // redirect
|
|
{
|
|
while (m_con->recv_lines_available() > 0)
|
|
{
|
|
m_con->recv_line(buf,4096);
|
|
if (!buf[0])
|
|
{
|
|
m_http_state=-1;
|
|
return -1;
|
|
}
|
|
if (!my_strnicmp(buf,"Location:",9))
|
|
{
|
|
char *p=buf+9; while (*p== ' ') p++;
|
|
if (*p)
|
|
{
|
|
connect(p);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (m_http_state==2)
|
|
{
|
|
if (!cnt++ && m_con->recv_lines_available() < 1) goto run_again;
|
|
while (m_con->recv_lines_available() > 0)
|
|
{
|
|
m_con->recv_line(buf,4096);
|
|
if (!buf[0]) { m_http_state=3; break; }
|
|
if (!m_recvheaders)
|
|
{
|
|
m_recvheaders_size=strlen(buf)+1;
|
|
m_recvheaders=(char*)malloc(m_recvheaders_size+1);
|
|
if (m_recvheaders)
|
|
{
|
|
strcpy(m_recvheaders,buf);
|
|
m_recvheaders[m_recvheaders_size]=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int oldsize=m_recvheaders_size;
|
|
m_recvheaders_size+=strlen(buf)+1;
|
|
char *n=(char*)malloc(m_recvheaders_size+1);
|
|
if (n)
|
|
{
|
|
memcpy(n,m_recvheaders,oldsize);
|
|
strcpy(n+oldsize,buf);
|
|
n[m_recvheaders_size]=0;
|
|
free(m_recvheaders);
|
|
m_recvheaders=n;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (m_http_state==3)
|
|
{
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int JNL_HTTPGet::get_status() // returns 0 if connecting, 1 if reading headers,
|
|
// 2 if reading content, -1 if error.
|
|
{
|
|
if (m_http_state < 0) return -1;
|
|
if (m_http_state < 2) return 0;
|
|
if (m_http_state == 2) return 1;
|
|
if (m_http_state == 3) return 2;
|
|
return -1;
|
|
}
|
|
|
|
int JNL_HTTPGet::getreplycode()// returns 0 if none yet, otherwise returns http reply code.
|
|
{
|
|
if (!m_reply) return 0;
|
|
char *p=m_reply;
|
|
while (*p && *p != ' ') p++; // skip over HTTP/x.x
|
|
if (!*p) return 0;
|
|
return my_atoi(++p);
|
|
}
|
|
|
|
int JNL_HTTPGet::bytes_available()
|
|
{
|
|
if (m_con && m_http_state==3) return m_con->recv_bytes_available();
|
|
return 0;
|
|
}
|
|
int JNL_HTTPGet::get_bytes(char *buf, int len)
|
|
{
|
|
if (m_con && m_http_state==3) return m_con->recv_bytes(buf,len);
|
|
return 0;
|
|
}
|
|
int JNL_HTTPGet::peek_bytes(char *buf, int len)
|
|
{
|
|
if (m_con && m_http_state==3) return m_con->peek_bytes(buf,len);
|
|
return 0;
|
|
}
|