http.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:22k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * http.cxx
  3.  *
  4.  * HTTP ancestor class and common classes.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: http.cxx,v $
  30.  * Revision 1.58  2000/05/02 08:29:07  craigs
  31.  * Removed "memory leaks" caused by brain-dead GNU linker
  32.  *
  33.  * Revision 1.57  1999/05/11 12:24:18  robertj
  34.  * Fixed URL parser so leading blanks are ignored.
  35.  *
  36.  * Revision 1.56  1999/05/04 15:26:01  robertj
  37.  * Improved HTTP/1.1 compatibility (pass through user commands).
  38.  * Fixed problems with quicktime installer.
  39.  *
  40.  * Revision 1.55  1999/04/21 01:56:13  robertj
  41.  * Fixed problem with escape codes greater that %80
  42.  *
  43.  * Revision 1.54  1999/01/16 12:45:54  robertj
  44.  * Added RTSP schemes to URL's
  45.  *
  46.  * Revision 1.53  1998/11/30 05:38:15  robertj
  47.  * Moved PURL::Open() code to .cxx file to avoid linking unused code.
  48.  *
  49.  * Revision 1.52  1998/11/30 04:51:53  robertj
  50.  * New directory structure
  51.  *
  52.  * Revision 1.51  1998/09/23 06:22:07  robertj
  53.  * Added open source copyright license.
  54.  *
  55.  * Revision 1.50  1998/02/03 10:02:34  robertj
  56.  * Added ability to get scheme, host and port from URL as a string.
  57.  *
  58.  * Revision 1.49  1998/02/03 06:27:26  robertj
  59.  * Fixed URL encoding to be closer to RFC
  60.  *
  61.  * Revision 1.48  1998/01/26 02:49:16  robertj
  62.  * GNU support.
  63.  *
  64.  * Revision 1.47  1997/11/10 12:40:20  robertj
  65.  * Fixed illegal character set for URL's.
  66.  *
  67.  * Revision 1.46  1997/07/14 11:47:10  robertj
  68.  * Added "const" to numerous variables.
  69.  *
  70.  * Revision 1.45  1997/07/12 09:45:01  robertj
  71.  * Fixed bug when URL has + sign in somthing other than parameters.
  72.  *
  73.  * Revision 1.44  1997/06/06 08:54:47  robertj
  74.  * Allowed username/password on http scheme URL.
  75.  *
  76.  * Revision 1.43  1997/04/06 07:46:09  robertj
  77.  * Fixed bug where URL has more than special character ('?', '#' etc).
  78.  *
  79.  * Revision 1.42  1997/03/28 04:40:24  robertj
  80.  * Added tags for cookies.
  81.  *
  82.  * Revision 1.41  1997/03/18 22:03:44  robertj
  83.  * Fixed bug that incorrectly parses URL with double slashes.
  84.  *
  85.  * Revision 1.40  1997/02/14 13:55:44  robertj
  86.  * Fixed bug in URL for reproducing fields with special characters, must be escaped and weren't.
  87.  *
  88.  * Revision 1.39  1997/01/12 04:15:21  robertj
  89.  * Globalised MIME tag strings.
  90.  *
  91.  * Revision 1.38  1996/09/14 13:09:28  robertj
  92.  * Major upgrade:
  93.  *   rearranged sockets to help support IPX.
  94.  *   added indirect channel class and moved all protocols to descend from it,
  95.  *   separating the protocol from the low level byte transport.
  96.  *
  97.  * Revision 1.37  1996/08/25 09:37:41  robertj
  98.  * Added function to detect "local" host name.
  99.  * Fixed printing of trailing '/' in empty URL, is distinction between with and without.
  100.  *
  101.  * Revision 1.36  1996/08/22 13:22:26  robertj
  102.  * Fixed bug in print of URLs, extra @ signs.
  103.  *
  104.  * Revision 1.35  1996/08/19 13:42:40  robertj
  105.  * Fixed errors in URL parsing and display.
  106.  * Fixed "Forbidden" problem out of HTTP authorisation system.
  107.  * Fixed authorisation so if have no user/password on basic authentication, does not require it.
  108.  *
  109.  * Revision 1.34  1996/07/27 04:13:47  robertj
  110.  * Fixed use of HTTP proxy on non-persistent connections.
  111.  *
  112.  * Revision 1.33  1996/07/15 10:37:20  robertj
  113.  * Improved proxy "self" detection (especially localhost).
  114.  *
  115.  * Revision 1.32  1996/06/28 13:20:24  robertj
  116.  * Modified HTTPAuthority so gets PHTTPReqest (mainly for URL) passed in.
  117.  * Moved HTTP form resource to another compilation module.
  118.  * Fixed memory leak in POST command.
  119.  *
  120.  * Revision 1.31  1996/06/10 10:00:00  robertj
  121.  * Added global function for query parameters parsing.
  122.  *
  123.  * Revision 1.30  1996/06/07 13:52:23  robertj
  124.  * Added PUT to HTTP proxy FTP. Necessitating redisign of entity body processing.
  125.  *
  126.  * Revision 1.29  1996/06/05 12:33:04  robertj
  127.  * Fixed bug in parsing URL with no path, is NOT absolute!
  128.  *
  129.  * Revision 1.28  1996/05/30 10:07:26  robertj
  130.  * Fixed bug in version number checking of return code compatibility.
  131.  *
  132.  * Revision 1.27  1996/05/26 03:46:42  robertj
  133.  * Compatibility to GNU 2.7.x
  134.  *
  135.  * Revision 1.26  1996/05/23 10:02:13  robertj
  136.  * Added common function for GET and HEAD commands.
  137.  * Fixed status codes to be the actual status code instead of sequential enum.
  138.  * This fixed some problems with proxy pass through of status codes.
  139.  * Fixed bug in URL parsing of username and passwords.
  140.  *
  141.  * Revision 1.19.1.1  1996/04/17 11:08:22  craigs
  142.  * New version by craig pending confirmation by robert
  143.  *
  144.  * Revision 1.19  1996/04/05 01:46:30  robertj
  145.  * Assured PSocket::Write always writes the number of bytes specified, no longer need write loops.
  146.  * Added workaraound for NT Netscape Navigator bug with persistent connections.
  147.  *
  148.  * Revision 1.18  1996/03/31 09:05:07  robertj
  149.  * HTTP 1.1 upgrade.
  150.  *
  151.  * Revision 1.17  1996/03/17 05:48:07  robertj
  152.  * Fixed host name print out of URLs.
  153.  * Added hit count to PHTTPResource.
  154.  *
  155.  * Revision 1.16  1996/03/16 05:00:26  robertj
  156.  * Added ParseReponse() for splitting reponse line into code and info.
  157.  * Added client side support for HTTP socket.
  158.  * Added hooks for proxy support in HTTP socket.
  159.  * Added translation type to TranslateString() to accommodate query variables.
  160.  * Defaulted scheme field in URL to "http".
  161.  * Inhibited output of port field on string conversion of URL according to scheme.
  162.  *
  163.  * Revision 1.15  1996/03/11 10:29:50  robertj
  164.  * Fixed bug in help image HTML.
  165.  *
  166.  * Revision 1.14  1996/03/10 13:15:24  robertj
  167.  * Redesign to make resources thread safe.
  168.  *
  169.  * Revision 1.13  1996/03/02 03:27:37  robertj
  170.  * Added function to translate a string to a form suitable for inclusion in a URL.
  171.  * Added radio button and selection boxes to HTTP form resource.
  172.  * Fixed bug in URL parsing, losing first / if hostname specified.
  173.  *
  174.  * Revision 1.12  1996/02/25 11:14:24  robertj
  175.  * Radio button support for forms.
  176.  *
  177.  * Revision 1.11  1996/02/25 03:10:34  robertj
  178.  * Removed pass through HTTP resource.
  179.  * Fixed PHTTPConfig resource to use correct name for config key.
  180.  *
  181.  * Revision 1.10  1996/02/19 13:48:28  robertj
  182.  * Put multiple uses of literal strings into const variables.
  183.  * Fixed URL parsing so that the unmangling of strings occurs correctly.
  184.  * Moved nested classes from PHTTPForm.
  185.  * Added overwrite option to AddResource().
  186.  * Added get/set string to PHTTPString resource.
  187.  *
  188.  * Revision 1.9  1996/02/13 13:09:17  robertj
  189.  * Added extra parameters to callback function in PHTTPResources, required
  190.  *   by descendants to make informed decisions on data being loaded.
  191.  *
  192.  * Revision 1.8  1996/02/08 12:26:29  robertj
  193.  * Redesign of resource callback mechanism.
  194.  * Added new resource types for HTML data entry forms.
  195.  *
  196.  * Revision 1.7  1996/02/03 11:33:19  robertj
  197.  * Changed RadCmd() so can distinguish between I/O error and unknown command.
  198.  *
  199.  * Revision 1.6  1996/02/03 11:11:49  robertj
  200.  * Numerous bug fixes.
  201.  * Added expiry date and ismodifiedsince support.
  202.  *
  203.  * Revision 1.5  1996/01/30 23:32:40  robertj
  204.  * Added single .
  205.  *
  206.  * Revision 1.4  1996/01/28 14:19:09  robertj
  207.  * Split HTML into separate source file.
  208.  * Beginning of pass through resource type.
  209.  * Changed PCharArray in OnLoadData to PString for convenience in mangling data.
  210.  * Made PHTTPSpace return standard page on selection of partial path.
  211.  *
  212.  * Revision 1.3  1996/01/28 02:49:16  robertj
  213.  * Further implementation.
  214.  *
  215.  * Revision 1.2  1996/01/26 02:24:30  robertj
  216.  * Further implemetation.
  217.  *
  218.  * Revision 1.1  1996/01/23 13:04:32  robertj
  219.  * Initial revision
  220.  *
  221.  */
  222. #ifdef __GNUC__
  223. #pragma implementation "http.h"
  224. #pragma implementation "url.h"
  225. #endif
  226. #include <ptlib.h>
  227. #include <ptlib/sockets.h>
  228. #include <ptclib/http.h>
  229. #include <ptclib/url.h>
  230. #include <ctype.h>
  231. // RFC 1738
  232. // http://host:port/path...
  233. // https://host:port/path....
  234. // gopher://host:port
  235. // wais://host:port
  236. // nntp://host:port
  237. // prospero://host:port
  238. // ftp://user:password@host:port/path...
  239. // telnet://user:password@host:port
  240. // file://hostname/path...
  241. // mailto:user@hostname
  242. // news:string
  243. #define DEFAULT_FTP_PORT 21
  244. #define DEFAULT_TELNET_PORT 23
  245. #define DEFAULT_GOPHER_PORT 70
  246. #define DEFAULT_HTTP_PORT 80
  247. #define DEFAULT_NNTP_PORT 119
  248. #define DEFAULT_WAIS_PORT 210
  249. #define DEFAULT_HTTPS_PORT 443
  250. #define DEFAULT_RTSP_PORT 554
  251. #define DEFAULT_RTSPU_PORT 554
  252. #define DEFAULT_PROSPERO_PORT 1525
  253. enum SchemeFormat {
  254.   HostPort = 1,
  255.   UserPasswordHostPort = 2,
  256.   HostOnly = 3,
  257.   Other = 4
  258. };
  259. class schemeStruct {
  260.   public:
  261.     const char * name;
  262.     int  type;
  263.     BOOL hasDoubleSlash;
  264.     WORD defaultPort;
  265. };
  266. static schemeStruct const schemeInfo[] = {
  267.   { "http",      UserPasswordHostPort, TRUE, DEFAULT_HTTP_PORT },
  268.   { "https",     HostPort, TRUE, DEFAULT_HTTPS_PORT },
  269.   { "gopher",    HostPort, TRUE, DEFAULT_GOPHER_PORT },
  270.   { "wais",      HostPort, TRUE, DEFAULT_WAIS_PORT },
  271.   { "nntp",      HostPort, TRUE, DEFAULT_NNTP_PORT },
  272.   { "prospero",  HostPort, TRUE, DEFAULT_PROSPERO_PORT },
  273.   { "rtsp",      HostPort, TRUE, DEFAULT_RTSP_PORT },
  274.   { "rtspu",     HostPort, TRUE, DEFAULT_RTSPU_PORT },
  275.   { "ftp",       UserPasswordHostPort, TRUE, DEFAULT_FTP_PORT },
  276.   { "telnet",    UserPasswordHostPort, TRUE, DEFAULT_TELNET_PORT },
  277.   { "file",      HostOnly,             TRUE },
  278.   { "mailto",    Other, FALSE},
  279.   { "news",      Other, FALSE},
  280.   { NULL }
  281. };
  282. static schemeStruct const defaultSchemeInfo = { "other", Other, FALSE};
  283. static const schemeStruct & GetSchemeInfo(const PString & scheme)
  284. {
  285.   PINDEX i;
  286.   for (i = 0; schemeInfo[i].name != NULL; i++)
  287.     if (scheme *= schemeInfo[i].name)
  288.       return schemeInfo[i];
  289.   return defaultSchemeInfo;
  290. }
  291. //////////////////////////////////////////////////////////////////////////////
  292. // PURL
  293. PURL::PURL()
  294. {
  295.   scheme = "http";
  296.   port   = 0;
  297. }
  298. PURL::PURL(const char * str)
  299. {
  300.   Parse(str);
  301. }
  302. PURL::PURL(const PString & str)
  303. {
  304.   Parse(str);
  305. }
  306. PObject::Comparison PURL::Compare(const PObject & obj) const
  307. {
  308.   PAssert(obj.IsDescendant(PURL::Class()), PInvalidCast);
  309.   const PURL & other = (const PURL &)obj;
  310.   Comparison c = scheme.Compare(other.scheme);
  311.   if (c == EqualTo) {
  312.     c = username.Compare(other.username);
  313.     if (c == EqualTo) {
  314.       c = password.Compare(other.password);
  315.       if (c == EqualTo) {
  316.         c = hostname.Compare(other.hostname);
  317.         if (c == EqualTo) {
  318.           c = pathStr.Compare(other.pathStr);
  319.           if (c == EqualTo) {
  320.             c = parameters.Compare(other.parameters);
  321.             if (c == EqualTo) {
  322.               c = fragment.Compare(other.fragment);
  323.               if (c == EqualTo)
  324.                 c = queryStr.Compare(other.queryStr);
  325.             }
  326.           }
  327.         }
  328.       }
  329.     }
  330.   }
  331.   return c;
  332. }
  333. PINDEX PURL::HashFunction() const
  334. {
  335.   return ((BYTE)toupper(scheme[0]) +
  336.           (BYTE)toupper(username[0]) +
  337.           (BYTE)toupper(password[0]) +
  338.           (BYTE)toupper(hostname[0]) +
  339.           (BYTE)toupper(pathStr[0]) +
  340.           (BYTE)toupper(parameters[0]) +
  341.           (BYTE)toupper(fragment[0]) +
  342.           (BYTE)toupper(queryStr[0]))%41;
  343. }
  344. void PURL::PrintOn(ostream & stream) const
  345. {
  346.   stream << AsString(FullURL);
  347. }
  348. void PURL::ReadFrom(istream & stream)
  349. {
  350.   PString s;
  351.   stream >> s;
  352.   Parse(s);
  353. }
  354. PString PURL::TranslateString(const PString & str, TranslationType type)
  355. {
  356.   PString xlat = str;
  357.   if (type == QueryTranslation) {
  358.     PINDEX space = (PINDEX)-1;
  359.     while ((space = xlat.Find(' ', space+1)) != P_MAX_INDEX)
  360.       xlat[space] = '+';
  361.   }
  362.   PString safeChars = "abcdefghijklmnopqrstuvwxyz"
  363.                       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  364.                       "0123456789$-_.+!*'(),";
  365.   switch (type) {
  366.     case LoginTranslation :
  367.       safeChars += ";?&=";
  368.       break;
  369.     case PathTranslation :
  370.       safeChars += ":@&=";
  371.       break;
  372.     case QueryTranslation :
  373.       safeChars += ":@";
  374.   }
  375.   PINDEX pos = (PINDEX)-1;
  376.   while ((pos += 1+strspn(&xlat[pos+1], safeChars)) < xlat.GetLength())
  377.     xlat.Splice(psprintf("%%%02X", (BYTE)xlat[pos]), pos, 1);
  378.   return xlat;
  379. }
  380. static void UnmangleString(PString & str, PURL::TranslationType type)
  381. {
  382.   PINDEX pos;
  383.   if (type == PURL::QueryTranslation) {
  384.     pos = (PINDEX)-1;
  385.     while ((pos = str.Find('+', pos+1)) != P_MAX_INDEX)
  386.       str[pos] = ' ';
  387.   }
  388.   pos = (PINDEX)-1;
  389.   while ((pos = str.Find('%', pos+1)) != P_MAX_INDEX) {
  390.     int digit1 = str[pos+1];
  391.     int digit2 = str[pos+2];
  392.     if (isxdigit(digit1) && isxdigit(digit2)) {
  393.       str[pos] = (char)(
  394.             (isdigit(digit2) ? (digit2-'0') : (toupper(digit2)-'A'+10)) +
  395.            ((isdigit(digit1) ? (digit1-'0') : (toupper(digit1)-'A'+10)) << 4));
  396.       str.Delete(pos+1, 2);
  397.     }
  398.   }
  399. }
  400. void PURL::SplitQueryVars(const PString & queryStr, PStringToString & queryVars)
  401. {
  402.   PStringArray tokens = queryStr.Tokenise("&=", TRUE);
  403.   for (PINDEX i = 0; i < tokens.GetSize(); i += 2) {
  404.     PCaselessString key = tokens[i];
  405.     UnmangleString(key, QueryTranslation);
  406.     PString data = tokens[i+1];
  407.     UnmangleString(data, QueryTranslation);
  408.     if (queryVars.Contains(key))
  409.       queryVars.SetAt(key, queryVars[key] + ',' + data);
  410.     else
  411.       queryVars.SetAt(key, data);
  412.   }
  413. }
  414. void PURL::Parse(const char * cstr)
  415. {
  416.   hostname = PCaselessString();
  417.   pathStr = username = password = parameters = fragment = queryStr = PString();
  418.   path.SetSize(0);
  419.   queryVars.RemoveAll();
  420.   port = 0;
  421.   // copy the string so we can take bits off it
  422.   while (isspace(*cstr))
  423.     cstr++;
  424.   PString url = cstr;
  425.   PINDEX pos;
  426.   static const PString reservedChars = "=;/#?";
  427.   // determine if the URL has a scheme
  428.   scheme = "";
  429.   if (isalpha(url[0])) {
  430.     for (pos = 0; url[pos] != '' &&
  431.                           reservedChars.Find(url[pos]) == P_MAX_INDEX; pos++) {
  432.       if (url[pos] == ':') {
  433.         scheme = url.Left(pos);
  434.         url.Delete(0, pos+1);
  435.         break;
  436.       }
  437.     }
  438.   }
  439.   // if there is no scheme, then default to http for the local
  440.   // on the default port
  441.   if (scheme.IsEmpty()) {
  442.     scheme   = "http";
  443.     if (url.GetLength() > 2 && url[0] == '/' && url[1] == '/') 
  444.       url.Delete(0, 2);
  445.   } else {
  446.     // get information which tells us how to parse URL for this
  447.     // particular scheme
  448.     const schemeStruct & schemeInfo = GetSchemeInfo(scheme);
  449.     
  450.     // if the URL should have leading slash, then remove it if it has one
  451.     if (schemeInfo.hasDoubleSlash &&
  452.       url.GetLength() > 2 && url[0] == '/' && url[1] == '/') 
  453.     url.Delete(0, 2);
  454.     // if the rest of the URL isn't a path, then we are finished!
  455.     if (schemeInfo.type == Other) {
  456.       pathStr = url;
  457.       return;
  458.     }
  459.     // parse user/password/host/port
  460.     if (schemeInfo.type == HostPort ||
  461.         schemeInfo.type == UserPasswordHostPort ||
  462.         schemeInfo.type == HostOnly) {
  463.       pos = url.Find('/');
  464.       PString uphp = url.Left(pos);
  465.       if (pos != P_MAX_INDEX)
  466.         url.Delete(0, pos);
  467.       else
  468.         url = PString();
  469.       // if the URL is of type HostOnly, then this is the hostname
  470.       if (schemeInfo.type == HostOnly) {
  471.         hostname = uphp;
  472.         UnmangleString(hostname, LoginTranslation);
  473.       } 
  474.       // if the URL is of type UserPasswordHostPort, then parse it
  475.       if (schemeInfo.type == UserPasswordHostPort) {
  476.         // extract username and password
  477.         PINDEX pos2 = uphp.Find('@');
  478.         if (pos2 != P_MAX_INDEX && pos2 > 0) {
  479.           PINDEX pos3 = uphp.Find(":");
  480.           // if no password...
  481.           if (pos3 > pos2)
  482.             username = uphp(0, pos2-1);
  483.           else {
  484.             username = uphp(0, pos3-1);
  485.             password = uphp(pos3+1, pos2-1);
  486.             UnmangleString(password, LoginTranslation);
  487.           }
  488.           UnmangleString(username, LoginTranslation);
  489.           uphp.Delete(0, pos2+1);
  490.         }
  491.       }
  492.       // determine if the URL has a port number
  493.       if (schemeInfo.type == HostPort ||
  494.           schemeInfo.type == UserPasswordHostPort) {
  495.         pos = uphp.Find(":");
  496.         if (pos == P_MAX_INDEX) {
  497.           hostname = uphp;
  498.           port = schemeInfo.defaultPort;
  499.         } else {
  500.           hostname = uphp.Left(pos);
  501.           port = (WORD)uphp(pos+1, P_MAX_INDEX).AsInteger();
  502.         }
  503.         UnmangleString(hostname, LoginTranslation);
  504.         if (hostname.IsEmpty())
  505.           hostname = PIPSocket::GetHostName();
  506.       }
  507.     }
  508.   }
  509.   // chop off any trailing fragment
  510.   pos = url.Find('#');
  511.   if (pos != P_MAX_INDEX && pos > 0) {
  512.     fragment = url(pos+1, P_MAX_INDEX);
  513.     UnmangleString(fragment, PathTranslation);
  514.     url.Delete(pos, P_MAX_INDEX);
  515.   }
  516.   // chop off any trailing query
  517.   pos = url.Find('?');
  518.   if (pos != P_MAX_INDEX && pos > 0) {
  519.     queryStr = url(pos+1, P_MAX_INDEX);
  520.     url.Delete(pos, P_MAX_INDEX);
  521.     SplitQueryVars(queryStr, queryVars);
  522.   }
  523.   // chop off any trailing parameters
  524.   pos = url.Find(';');
  525.   if (pos != P_MAX_INDEX && pos > 0) {
  526.     parameters = url(pos+1, P_MAX_INDEX);
  527.     UnmangleString(parameters, PathTranslation);
  528.     url.Delete(pos, P_MAX_INDEX);
  529.   }
  530.   // the hierarchy is what is left
  531.   pathStr = url;
  532.   path = url.Tokenise("/", TRUE);
  533.   if (path.GetSize() > 0 && path[0].IsEmpty()) 
  534.     path.RemoveAt(0);
  535.   for (pos = 0; pos < path.GetSize(); pos++) {
  536.     UnmangleString(path[pos], PathTranslation);
  537.     if (pos > 0 && path[pos] == ".." && path[pos-1] != "..") {
  538.       path.RemoveAt(pos--);
  539.       path.RemoveAt(pos--);
  540.     }
  541.   }
  542. }
  543. PString PURL::AsString(UrlFormat fmt) const
  544. {
  545.   PStringStream str;
  546.   if (fmt == FullURL || fmt == HostPortOnly) {
  547.     // if the scheme is empty, assume http
  548.     if (!scheme) {
  549.       str << scheme << ':';
  550.       const schemeStruct & schemeInfo = GetSchemeInfo(scheme);
  551.       if (schemeInfo.hasDoubleSlash)
  552.         str << "//";
  553.       if (schemeInfo.type == Other) 
  554.         str << pathStr;
  555.       else {
  556.         if (schemeInfo.type == HostOnly)
  557.           str << hostname;
  558.         if (schemeInfo.type == UserPasswordHostPort) {
  559.           if (!username || !password)
  560.             str << TranslateString(username, LoginTranslation)
  561.                 << ':'
  562.                 << TranslateString(password, LoginTranslation)
  563.                 << '@';
  564.         }
  565.         if (schemeInfo.type == HostPort || schemeInfo.type == UserPasswordHostPort) {
  566.           if (hostname.IsEmpty())
  567.             str = PString();
  568.           else {
  569.             str << hostname;
  570.             if (port != schemeInfo.defaultPort)
  571.               str << ':' << port;
  572.           }
  573.         }
  574.       }
  575.     }
  576.     if (fmt == HostPortOnly)
  577.       return str;
  578.   }
  579.   PINDEX count = path.GetSize();
  580.   if (count > 0) {
  581.     str << '/';
  582.     for (PINDEX i = 0; i < count; i++) {
  583.       str << TranslateString(path[i], PathTranslation);
  584.       if (i < count-1)
  585.         str << '/';
  586.     }
  587.   }
  588.   if (fmt == FullURL || fmt == URIOnly) {
  589.     if (!parameters)
  590.       str << ";" << TranslateString(parameters, PathTranslation);
  591.     if (!queryStr)
  592.       str << "?" << queryStr;
  593.     if (!fragment)
  594.       str << "#" << TranslateString(fragment, PathTranslation);
  595.   }
  596.   return str;
  597. }
  598. BOOL PURL::OpenBrowser(const PString & url)
  599. {
  600. #ifdef WIN32
  601.   if ((int)ShellExecute(NULL, "open", url, NULL, NULL, 0) > 32)
  602.     return TRUE;
  603.   MessageBox(NULL, "Unable to open page"&url, PProcess::Current().GetName(), MB_TASKMODAL);
  604. #endif
  605.   return FALSE;
  606. }
  607. //////////////////////////////////////////////////////////////////////////////
  608. // PHTTP
  609. static char const * const HTTPCommands[PHTTP::NumCommands] = {
  610.   // HTTP 1.0 commands
  611.   "GET", "HEAD", "POST",
  612.   // HTTP 1.1 commands
  613.   "PUT",  "DELETE", "TRACE", "OPTIONS",
  614.   // HTTPS command
  615.   "CONNECT"
  616. };
  617. const char * PHTTP::AllowTag           = "Allow";
  618. const char * PHTTP::AuthorizationTag   = "Authorization";
  619. const char * PHTTP::ContentEncodingTag = "Content-Encoding";
  620. const char * PHTTP::ContentLengthTag   = "Content-Length";
  621. const char * PHTTP::ContentTypeTag     = "Content-Type";
  622. const char * PHTTP::DateTag            = "Date";
  623. const char * PHTTP::ExpiresTag         = "Expires";
  624. const char * PHTTP::FromTag            = "From";
  625. const char * PHTTP::IfModifiedSinceTag = "If-Modified-Since";
  626. const char * PHTTP::LastModifiedTag    = "Last-Modified";
  627. const char * PHTTP::LocationTag        = "Location";
  628. const char * PHTTP::PragmaTag          = "Pragma";
  629. const char * PHTTP::PragmaNoCacheTag   = "no-cache";
  630. const char * PHTTP::RefererTag         = "Referer";
  631. const char * PHTTP::ServerTag          = "Server";
  632. const char * PHTTP::UserAgentTag       = "User-Agent";
  633. const char * PHTTP::WWWAuthenticateTag = "WWW-Authenticate";
  634. const char * PHTTP::MIMEVersionTag     = "MIME-Version";
  635. const char * PHTTP::ConnectionTag      = "Connection";
  636. const char * PHTTP::KeepAliveTag       = "Keep-Alive";
  637. const char * PHTTP::ProxyConnectionTag = "Proxy-Connection";
  638. const char * PHTTP::ProxyAuthorizationTag = "Proxy-Authorization";
  639. const char * PHTTP::ProxyAuthenticateTag = "Proxy-Authenticate";
  640. const char * PHTTP::ForwardedTag       = "Forwarded";
  641. const char * PHTTP::SetCookieTag       = "Set-Cookie";
  642. const char * PHTTP::CookieTag          = "Cookie";
  643. PHTTP::PHTTP()
  644.   : PInternetProtocol("www 80", NumCommands, HTTPCommands)
  645. {
  646. }
  647. PINDEX PHTTP::ParseResponse(const PString & line)
  648. {
  649.   PINDEX endVer = line.Find(' ');
  650.   if (endVer == P_MAX_INDEX) {
  651.     lastResponseInfo = "Bad response";
  652.     lastResponseCode = PHTTP::InternalServerError;
  653.     return 0;
  654.   }
  655.   lastResponseInfo = line.Left(endVer);
  656.   PINDEX endCode = line.Find(' ', endVer+1);
  657.   lastResponseCode = line(endVer+1,endCode-1).AsInteger();
  658.   if (lastResponseCode == 0)
  659.     lastResponseCode = PHTTP::InternalServerError;
  660.   lastResponseInfo &= line.Mid(endCode);
  661.   return 0;
  662. }
  663. // End Of File ///////////////////////////////////////////////////////////////