home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 March / CMCD0304.ISO / Software / Freeware / Programare / nullsoft / nsis20.exe / Contrib / NSISdl / httpget.cpp < prev    next >
C/C++ Source or Header  |  2003-12-01  |  10KB  |  473 lines

  1. /*
  2. ** JNetLib
  3. ** Copyright (C) 2000-2001 Nullsoft, Inc.
  4. ** Author: Justin Frankel
  5. ** File: httpget.cpp - JNL HTTP GET implementation
  6. ** License: see jnetlib.h
  7. */
  8.  
  9. #include "netinc.h"
  10. #include "util.h"
  11. #include "httpget.h"
  12.  
  13.  
  14. JNL_HTTPGet::JNL_HTTPGet(JNL_AsyncDNS *dns, int recvbufsize, char *proxy)
  15. {
  16.   m_recvbufsize=recvbufsize;
  17.   m_dns=dns;
  18.   m_con=NULL;
  19.   m_http_proxylpinfo=0;
  20.   m_http_proxyhost=0;
  21.   m_http_proxyport=0;
  22.   if (proxy && *proxy)
  23.   {
  24.     char *p=(char*)malloc(strlen(proxy)+1);
  25.     if (p) 
  26.     {
  27.       char *r=NULL;
  28.       strcpy(p,proxy);
  29.       do_parse_url(p,&m_http_proxyhost,&m_http_proxyport,&r,&m_http_proxylpinfo);
  30.       free(r);
  31.       free(p);
  32.     }
  33.   }
  34.   m_sendheaders=NULL;
  35.   reinit();
  36. }
  37.  
  38. void JNL_HTTPGet::reinit()
  39. {
  40.   m_errstr=0;
  41.   m_recvheaders=NULL;
  42.   m_recvheaders_size=0;
  43.   m_http_state=0;
  44.   m_http_port=0;
  45.   m_http_url=0;
  46.   m_reply=0;
  47.   m_http_host=m_http_lpinfo=m_http_request=NULL;
  48. }
  49.  
  50. void JNL_HTTPGet::deinit()
  51. {
  52.   delete m_con;
  53.   free(m_recvheaders);
  54.  
  55.   free(m_http_url);
  56.   free(m_http_host);
  57.   free(m_http_lpinfo);
  58.   free(m_http_request);
  59.   free(m_errstr);
  60.   free(m_reply);
  61.   reinit();
  62. }
  63.  
  64. JNL_HTTPGet::~JNL_HTTPGet()
  65. {
  66.   deinit();
  67.   free(m_sendheaders);
  68.   free(m_http_proxylpinfo);
  69.   free(m_http_proxyhost);
  70.  
  71. }
  72.  
  73.  
  74. void JNL_HTTPGet::addheader(char *header)
  75. {
  76.   //if (strstr(header,"\r") || strstr(header,"\n")) return;
  77.   if (!m_sendheaders)
  78.   {
  79.     m_sendheaders=(char*)malloc(strlen(header)+3);
  80.     if (m_sendheaders) 
  81.     {
  82.       strcpy(m_sendheaders,header);
  83.       strcat(m_sendheaders,"\r\n");
  84.     }
  85.   }
  86.   else
  87.   {
  88.     char *t=(char*)malloc(strlen(header)+strlen(m_sendheaders)+1+2);
  89.     if (t)
  90.     {
  91.       strcpy(t,m_sendheaders);
  92.       strcat(t,header);
  93.       strcat(t,"\r\n");
  94.       free(m_sendheaders);
  95.       m_sendheaders=t;
  96.     }
  97.   }
  98. }
  99.  
  100. void JNL_HTTPGet::do_encode_mimestr(char *in, char *out)
  101. {
  102.   char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  103.   int shift = 0;
  104.   int accum = 0;
  105.  
  106.   while (*in)
  107.   {
  108.     if (*in)
  109.     {
  110.       accum <<= 8;
  111.       shift += 8;
  112.       accum |= *in++;
  113.     }
  114.     while ( shift >= 6 )
  115.     {
  116.       shift -= 6;
  117.       *out++ = alphabet[(accum >> shift) & 0x3F];
  118.     }
  119.   }
  120.   if (shift == 4)
  121.   {
  122.     *out++ = alphabet[(accum & 0xF)<<2];
  123.     *out++='=';  
  124.   }
  125.   else if (shift == 2)
  126.   {
  127.     *out++ = alphabet[(accum & 0x3)<<4];
  128.     *out++='=';  
  129.     *out++='=';  
  130.   }
  131.  
  132.   *out++=0;
  133. }
  134.  
  135.  
  136. void JNL_HTTPGet::connect(char *url)
  137. {
  138.   deinit();
  139.   m_http_url=(char*)malloc(strlen(url)+1);
  140.   strcpy(m_http_url,url);
  141.   do_parse_url(m_http_url,&m_http_host,&m_http_port,&m_http_request, &m_http_lpinfo);
  142.   strcpy(m_http_url,url);
  143.   if (!m_http_host || !m_http_host[0] || !m_http_port)
  144.   {
  145.     m_http_state=-1;
  146.     seterrstr("invalid URL");
  147.     return;
  148.   }
  149.  
  150.   int sendbufferlen=0;
  151.  
  152.   if (!m_http_proxyhost || !m_http_proxyhost[0])
  153.   {
  154.     sendbufferlen += 4 /* GET */ + strlen(m_http_request) + 9 /* HTTP/1.0 */ + 2;
  155.   }
  156.   else
  157.   {
  158.     sendbufferlen += 4 /* GET */ + strlen(m_http_url) + 9 /* HTTP/1.0 */ + 2;
  159.     if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
  160.     {
  161.       sendbufferlen+=58+strlen(m_http_proxylpinfo)*2; // being safe here
  162.     }
  163.   }
  164.   sendbufferlen += 5 /* Host: */ + strlen(m_http_host) + 2;
  165.  
  166.   if (m_http_lpinfo&&m_http_lpinfo[0])
  167.   {
  168.     sendbufferlen+=46+strlen(m_http_lpinfo)*2; // being safe here
  169.   }
  170.  
  171.   if (m_sendheaders) sendbufferlen+=strlen(m_sendheaders);
  172.  
  173.   char *str=(char*)malloc(sendbufferlen+1024);
  174.   if (!str)
  175.   {
  176.     seterrstr("error allocating memory");
  177.     m_http_state=-1;    
  178.   }
  179.  
  180.   if (!m_http_proxyhost || !m_http_proxyhost[0])
  181.   {
  182.     wsprintf(str,"GET %s HTTP/1.0\r\n",m_http_request);
  183.   }
  184.   else
  185.   {
  186.     wsprintf(str,"GET %s HTTP/1.0\r\n",m_http_url);
  187.   }
  188.  
  189.   wsprintf(str+strlen(str),"Host: %s\r\n",m_http_host);
  190.  
  191.   if (m_http_lpinfo&&m_http_lpinfo[0])
  192.   {
  193.     strcat(str,"Authorization: Basic ");
  194.     do_encode_mimestr(m_http_lpinfo,str+strlen(str));
  195.     strcat(str,"\r\n");
  196.   }
  197.   if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
  198.   {
  199.     strcat(str,"Proxy-Authorization: Basic ");
  200.     do_encode_mimestr(m_http_proxylpinfo,str+strlen(str));
  201.     strcat(str,"\r\n");
  202.   }
  203.  
  204.   if (m_sendheaders) strcat(str,m_sendheaders);
  205.   strcat(str,"\r\n");
  206.  
  207.   int a=m_recvbufsize;
  208.   if (a < 4096) a=4096;
  209.   m_con=new JNL_Connection(m_dns,strlen(str)+4,a);
  210.   if (m_con)
  211.   {
  212.     if (!m_http_proxyhost || !m_http_proxyhost[0])
  213.     {
  214.       m_con->connect(m_http_host,m_http_port);
  215.     }
  216.     else
  217.     {
  218.       m_con->connect(m_http_proxyhost,m_http_proxyport);
  219.     }
  220.     m_con->send_string(str);
  221.   }
  222.   else
  223.   {
  224.     m_http_state=-1;
  225.     seterrstr("could not create connection object");
  226.   }
  227.   free(str);
  228.  
  229. }
  230.  
  231. static int _strnicmp(char *b1, char *b2, int l)
  232. {
  233.   while (l-- && *b1 && *b2)
  234.   {
  235.     char bb1=*b1++;
  236.     char bb2=*b2++;
  237.     if (bb1>='a' && bb1 <= 'z') bb1+='A'-'a';
  238.     if (bb2>='a' && bb2 <= 'z') bb2+='A'-'a';
  239.     if (bb1 != bb2) return bb1-bb2;
  240.   }
  241.   return 0;
  242. }
  243.  
  244. char *_strstr(char *i, char *s)
  245. {
  246.   if (strlen(i)>=strlen(s)) while (i[strlen(s)-1])
  247.   {
  248.     int l=strlen(s)+1;
  249.     char *ii=i;
  250.     char *is=s;
  251.     while (--l>0)
  252.     {
  253.       if (*ii != *is) break;
  254.       ii++;
  255.       is++;
  256.     }
  257.     if (l==0) return i;
  258.     i++;
  259.   }
  260.   return NULL;
  261. }
  262.  
  263. #define strstr _strstr
  264.  
  265. void JNL_HTTPGet::do_parse_url(char *url, char **host, int *port, char **req, char **lp)
  266. {
  267.   char *p,*np;
  268.   free(*host); *host=0;
  269.   free(*req); *req=0;
  270.   free(*lp); *lp=0;
  271.  
  272.   if (strstr(url,"://")) np=p=strstr(url,"://")+3;
  273.   else np=p=url;
  274.   while (*np != '/' && *np) np++;
  275.   if (*np)
  276.   {
  277.     *req=(char*)malloc(strlen(np)+1);
  278.     if (*req) strcpy(*req,np);
  279.     *np++=0;
  280.   } 
  281.   else 
  282.   {
  283.     *req=(char*)malloc(2);
  284.     if (*req) strcpy(*req,"/");
  285.   }
  286.  
  287.   np=p;
  288.   while (*np != '@' && *np) np++;
  289.   if (*np)
  290.   {
  291.     *np++=0;
  292.     *lp=(char*)malloc(strlen(p)+1);
  293.     if (*lp) strcpy(*lp,p);
  294.     p=np;
  295.   }
  296.   else 
  297.   {
  298.     *lp=(char*)malloc(1);
  299.     if (*lp) strcpy(*lp,"");
  300.   }
  301.   np=p;
  302.   while (*np != ':' && *np) np++;
  303.   if (*np)
  304.   {
  305.     *np++=0;
  306.     *port=my_atoi(np);
  307.   } else *port=80;
  308.   *host=(char*)malloc(strlen(p)+1);
  309.   if (*host) strcpy(*host,p);
  310. }
  311.  
  312.  
  313. char *JNL_HTTPGet::getallheaders()
  314. { // double null terminated, null delimited list
  315.   if (m_recvheaders) return m_recvheaders;
  316.   else return "\0\0";
  317. }
  318.  
  319. char *JNL_HTTPGet::getheader(char *headername)
  320. {
  321.   char *ret=NULL;
  322.   if (strlen(headername)<1||!m_recvheaders) return NULL;
  323.   char *p=m_recvheaders;
  324.   while (*p)
  325.   {
  326.     if (!_strnicmp(headername,p,strlen(headername)))
  327.     {
  328.       ret=p+strlen(headername);
  329.       while (*ret == ' ') ret++;
  330.       break;
  331.     }
  332.     p+=strlen(p)+1;
  333.   }
  334.   return ret;
  335. }
  336.  
  337. int JNL_HTTPGet::run()
  338. {
  339.   int cnt=0;
  340.   if (m_http_state==-1||!m_con) return -1; // error
  341.  
  342.  
  343. run_again:
  344.   static char main_buf[4096];
  345.   char *buf = main_buf;
  346.   m_con->run();
  347.  
  348.   if (m_con->get_state()==JNL_Connection::STATE_ERROR)
  349.   {
  350.     seterrstr(m_con->get_errstr());
  351.     return -1;
  352.   }
  353.   if (m_con->get_state()==JNL_Connection::STATE_CLOSED) return 1;
  354.  
  355.   if (m_http_state==0) // connected, waiting for reply
  356.   {
  357.     if (m_con->recv_lines_available()>0)
  358.     {
  359.       m_con->recv_line(buf,4095);
  360.       buf[4095]=0;
  361.       m_reply=(char*)malloc(strlen(buf)+1);
  362.       strcpy(m_reply,buf);
  363.  
  364.       if (strstr(buf,"200")) m_http_state=2; // proceed to read headers normally
  365.       else if (strstr(buf,"301") || strstr(buf,"302")) 
  366.       {
  367.         m_http_state=1; // redirect city
  368.       }
  369.       else 
  370.       {
  371.         seterrstr(buf);
  372.         m_http_state=-1;
  373.         return -1;
  374.       }
  375.       cnt=0;
  376.     }
  377.     else if (!cnt++) goto run_again;
  378.   }
  379.   if (m_http_state == 1) // redirect
  380.   {
  381.     while (m_con->recv_lines_available() > 0)
  382.     {
  383.       m_con->recv_line(buf,4096);
  384.       if (!buf[0])  
  385.       {
  386.         m_http_state=-1;
  387.         return -1;
  388.       }
  389.       if (!_strnicmp(buf,"Location:",9))
  390.       {
  391.         char *p=buf+9; while (*p== ' ') p++;
  392.         if (*p)
  393.         {
  394.           connect(p);
  395.           return 0;
  396.         }
  397.       }
  398.     }
  399.   }
  400.   if (m_http_state==2)
  401.   {
  402.     if (!cnt++ && m_con->recv_lines_available() < 1) goto run_again;
  403.     while (m_con->recv_lines_available() > 0)
  404.     {
  405.       m_con->recv_line(buf,4096);
  406.       if (!buf[0]) { m_http_state=3; break; }
  407.       if (!m_recvheaders)
  408.       {
  409.         m_recvheaders_size=strlen(buf)+1;
  410.         m_recvheaders=(char*)malloc(m_recvheaders_size+1);
  411.         if (m_recvheaders)
  412.         {
  413.           strcpy(m_recvheaders,buf);
  414.           m_recvheaders[m_recvheaders_size]=0;
  415.         }
  416.       }
  417.       else
  418.       {
  419.         int oldsize=m_recvheaders_size;
  420.         m_recvheaders_size+=strlen(buf)+1;
  421.         char *n=(char*)malloc(m_recvheaders_size+1);
  422.         if (n)
  423.         {
  424.           memcpy(n,m_recvheaders,oldsize);
  425.           strcpy(n+oldsize,buf);
  426.           n[m_recvheaders_size]=0;
  427.           free(m_recvheaders);
  428.           m_recvheaders=n;
  429.         }
  430.       }
  431.     }
  432.   }
  433.   if (m_http_state==3)
  434.   {
  435.   }
  436.   return 0;
  437. }
  438.  
  439. int JNL_HTTPGet::get_status() // returns 0 if connecting, 1 if reading headers, 
  440.                     // 2 if reading content, -1 if error.
  441. {
  442.   if (m_http_state < 0) return -1;
  443.   if (m_http_state < 2) return 0;
  444.   if (m_http_state == 2) return 1;
  445.   if (m_http_state == 3) return 2;
  446.   return -1;
  447. }
  448.  
  449. int JNL_HTTPGet::getreplycode()// returns 0 if none yet, otherwise returns http reply code.
  450. {
  451.   if (!m_reply) return 0;
  452.   char *p=m_reply;
  453.   while (*p && *p != ' ') p++; // skip over HTTP/x.x
  454.   if (!*p) return 0;
  455.   return my_atoi(++p);
  456. }
  457.  
  458. int JNL_HTTPGet::bytes_available()
  459. {
  460.   if (m_con && m_http_state==3) return m_con->recv_bytes_available();
  461.   return 0;
  462. }
  463. int JNL_HTTPGet::get_bytes(char *buf, int len)
  464. {
  465.   if (m_con && m_http_state==3) return m_con->recv_bytes(buf,len);
  466.   return 0;
  467. }
  468. int JNL_HTTPGet::peek_bytes(char *buf, int len)
  469. {
  470.   if (m_con && m_http_state==3) return m_con->peek_bytes(buf,len);
  471.   return 0;
  472. }
  473.