home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mkhttp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  109.3 KB  |  3,785 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  * state machine to speak HTTP
  20.  *
  21.  * Designed and implemented by Lou Montulli '94
  22.  * Additions/Changes by Judson Valeski, Gagan Saksena 1997
  23.  */
  24. #include "rosetta.h"
  25. #include "mkutils.h"
  26. #include "mkpadpac.h"
  27.  
  28. #include "merrors.h"
  29.  
  30. #include "mkgeturl.h"
  31. #include "mkhttp.h"
  32. #include "shist.h"
  33. #include "glhist.h"
  34. #include "mkparse.h"
  35. #include "mktcp.h"
  36. #include "mkstream.h"
  37. #include "mkformat.h"
  38. #include "mkaccess.h"
  39. #include "mkcache.h"
  40. #include "mkautocf.h"
  41. #include "secnav.h"
  42. #include "cert.h"
  43. #include "ssl.h"
  44. #include "jscookie.h"
  45. #include "prefapi.h"
  46. #include "xp_error.h"
  47. #include "libi18n.h"
  48. #include "prtime.h"
  49.  
  50.  
  51. /* for XP_GetString() */
  52. #include "xpgetstr.h"
  53. extern int MK_REDIRECT_ATTEMPT_NOT_ALLOWED;
  54. extern int MK_HTTP_TYPE_CONFLICT;
  55. extern int MK_OUT_OF_MEMORY;
  56. extern int MK_TCP_READ_ERROR;
  57. extern int MK_TCP_WRITE_ERROR;
  58. extern int MK_CONNECTION_REFUSED;
  59. extern int MK_CONNECTION_TIMED_OUT;
  60. extern int MK_UNABLE_TO_CONNECT;
  61. extern int MK_UNABLE_TO_CONNECT_TO_PROXY;
  62. extern int MK_UNABLE_TO_LOCATE_HOST;
  63. extern int MK_UNABLE_TO_LOCATE_FILE;
  64. extern int MK_UNABLE_TO_OPEN_FILE;
  65. extern int MK_ZERO_LENGTH_FILE;
  66. extern int MK_COMPUSERVE_AUTH_FAILED;
  67. extern int XP_ALERT_UNKNOWN_STATUS;
  68. extern int XP_ERRNO_EWOULDBLOCK;
  69. extern int XP_PROGRESS_TRANSFER_DATA;
  70. extern int XP_PROGRESS_TRYAGAIN;
  71. extern int XP_PROGRESS_WAIT_REPLY;
  72. extern int XP_HR_TRANSFER_INTERRUPTED;
  73. extern int XP_TRANSFER_INTERRUPTED;
  74. extern int XP_ERRNO_EIO;            
  75.  
  76.  
  77. #ifdef PROFILE
  78. #pragma profile on
  79. #endif
  80.  
  81. #define VERSION_STRING "HTTP/1.1"
  82.  
  83. #define MAX_CACHED_HTTP_CONNECTIONS 4
  84.  
  85. /* the maximum size of a HTTP servers first line of response
  86.  */
  87. #define MAX_FIRST_LINE_SIZE 250
  88.  
  89. /* temporary
  90.  */
  91. #if defined(XP_WIN) || defined(XP_OS2)                      /* IBM-SAH */
  92. PUBLIC char *XP_AppName = 0;
  93. PUBLIC char *XP_AppCodeName = 0;
  94. PUBLIC char *XP_AppVersion = 0;
  95. PUBLIC char *XP_AppLanguage = 0;
  96. PUBLIC char *XP_AppPlatform = 0;
  97. #else
  98. PUBLIC CONST char *XP_AppName = 0;
  99. PUBLIC CONST char *XP_AppCodeName = 0;
  100. PUBLIC CONST char *XP_AppVersion = 0;
  101. PUBLIC CONST char *XP_AppLanguage = 0;
  102. PUBLIC CONST char *XP_AppPlatform = 0;
  103. #endif
  104.  
  105. PUBLIC char * FE_UsersFromField=0;    /* User's name/email address not used yet */
  106.  
  107. PRIVATE XP_List * http_connection_list=0;
  108. PRIVATE IdentifyMeEnum http_identification_method = DoNotIdentifyMe;
  109. PRIVATE Bool sendRefererHeader=TRUE;
  110.  
  111. /* definitions of state for the state machine design
  112.  */
  113. typedef enum {
  114.     HTTP_START_CONNECT,
  115.     HTTP_FINISH_CONNECT,
  116.     HTTP_SEND_SSL_PROXY_REQUEST,
  117.     HTTP_BEGIN_UPLOAD_FILE,
  118.     HTTP_SEND_REQUEST,
  119.     HTTP_SEND_POST_DATA,
  120.     HTTP_PARSE_FIRST_LINE,
  121.     HTTP_PARSE_MIME_HEADERS,
  122.     HTTP_SETUP_STREAM,
  123.     HTTP_BEGIN_PUSH_PARTIAL_CACHE_FILE,
  124.     HTTP_PUSH_PARTIAL_CACHE_FILE,
  125.     HTTP_PULL_DATA,
  126.     HTTP_DONE,
  127.     HTTP_ERROR_DONE,
  128. HG93634
  129.     HTTP_FREE
  130. } StatesEnum;
  131.  
  132. /* structure to hold data about a tcp connection
  133.  * to a news host
  134.  */
  135. typedef struct _HTTPConnection {
  136.     char   *hostname;       /* hostname string (may contain :port) */
  137.     PRFileDesc *sock;           /* socket */
  138.     XP_Bool busy;           /* is the connection in use already? */
  139.     XP_Bool prev_cache;     /* did this connection come from the cache? */
  140.     XP_Bool secure;         /* is it a secure connection? */
  141. } HTTPConnection;
  142.  
  143. typedef enum {
  144.     POINT_NINE,
  145.     ONE_POINT_O,
  146.     ONE_POINT_ONE
  147. } HTTP_Version;
  148.  
  149. /* structure to hold data pertaining to the active state of
  150.  * a transfer in progress.
  151.  *
  152.  */
  153. typedef struct _HTTPConData {
  154.     StatesEnum  next_state;       /* the next state or action to be taken */
  155.     char *      proxy_server;     /* name of proxy server if any */
  156.     char *        proxy_conf;       /* proxy config ptr from proxy autoconfig */
  157.     char *      line_buffer;      /* temporary string storage */
  158.     char *      server_headers;   /* headers from the server for 
  159.                                    * the proxy client
  160.                                    */
  161.     char *      orig_host;        /* if the host gets modified
  162.                                    * for my "netscape" -> "www.netscape.com"
  163.                                    * hack, the original host gets put here
  164.                                    */
  165.     XP_File     partial_cache_fp;
  166.     int32       partial_needed;      /* the part missing from the cache */
  167.  
  168.     int32        total_size_of_files_to_post;
  169.     int32       total_amt_written;
  170.  
  171.     int32       line_buffer_size; /* current size of the line buffer */
  172.     
  173.     HTTPConnection *connection;   /* struct to hold info about connection */
  174.  
  175.     NET_StreamClass * stream; /* The output stream */
  176.     Bool     pause_for_read;   /* Pause now for next read? */
  177.     Bool     send_http1;       /* should we send http/1.1? */
  178.     Bool     acting_as_proxy;  /* are we acting as a proxy? */
  179.     Bool     server_busy_retry; /* should we retry the get? */
  180.     Bool     posting;          /* are we posting? */
  181.     Bool     doing_redirect;   /* are we redirecting? */
  182.     Bool     save_redirect_method;   /* don't change METHOD when redirecting */
  183.     Bool     sent_authorization;     /* did we send auth with the request? */
  184.     Bool     sent_proxy_auth;         /* did we send proxy auth with the req? */
  185.     Bool     authorization_required; /* did we get a 401 auth return code? */
  186.     Bool     proxy_auth_required;    /* did we get a 407 auth return code? */
  187.     Bool     destroy_graph_progress; /* destroy graph progress? */
  188.     Bool     destroy_file_upload_progress_dialog;  
  189.     HTTP_Version  protocol_version;       /* .9 1.0 or 1.1 */ 
  190.     int32    original_content_length; /* the content length at the time of
  191.                                        * calling graph progress
  192.                                        */
  193.     TCP_ConData *tcp_con_data;  /* Data pointer for tcp connect state machine */
  194.     Bool         use_ssl_proxy;          /* should we use the SSL proxy? */
  195.     Bool         ssl_proxy_setup_done;   /* is setup done */
  196.     Bool         use_copy_from_cache;    /* did we get a 304? */
  197.     Bool         displayed_some_data;    /* have we displayed any data? */
  198.     Bool         save_connection;        /* save this connection for reuse? */
  199.     Bool         partial_cache_file;
  200.     Bool         reuse_stream;
  201.     Bool         connection_is_valid;
  202. #ifdef XP_WIN
  203.     Bool         calling_netlib_all_the_time;  /* is SetCallNetlibAllTheTime set? */
  204. #endif
  205.     void        *write_post_data_data;   /* a data object 
  206.                                           * for the WritePostData function 
  207.                                           */
  208. } HTTPConData;
  209.  
  210. /* macro's to simplify variable names */
  211. #define CD_NEXT_STATE              cd->next_state
  212. #define CD_PROXY_SERVER            cd->proxy_server
  213. #define CD_PROXY_CONF                cd->proxy_conf
  214. #define CD_LINE_BUFFER             cd->line_buffer
  215. #define CD_SERVER_HEADERS          cd->server_headers
  216. #define CD_LINE_BUFFER_SIZE        cd->line_buffer_size
  217. #define CD_STREAM                   cd->stream
  218. #define CD_SEND_HTTP1              cd->send_http1
  219. #define CD_PAUSE_FOR_READ          cd->pause_for_read
  220. #define CD_ACTING_AS_PROXY         cd->acting_as_proxy
  221. #define CD_SERVER_BUSY_RETRY      cd->server_busy_retry
  222. #define CD_POSTING                  cd->posting
  223. #define CD_DOING_REDIRECT          cd->doing_redirect
  224. #define CD_SENT_AUTHORIZATION     cd->sent_authorization
  225. #define CD_SENT_PROXY_AUTH        cd->sent_proxy_auth
  226. #define CD_AUTH_REQUIRED           cd->authorization_required
  227. #define CD_PROXY_AUTH_REQUIRED    cd->proxy_auth_required
  228. #define CD_DESTROY_GRAPH_PROGRESS   cd->destroy_graph_progress
  229. #define CD_ORIGINAL_CONTENT_LENGTH  cd->original_content_length
  230. #define CD_TCP_CON_DATA              cd->tcp_con_data
  231. #define CD_USE_SSL_PROXY          cd->use_ssl_proxy
  232. #define CD_SSL_PROXY_SETUP_DONE   cd->ssl_proxy_setup_done
  233. #define CD_USE_COPY_FROM_CACHE    cd->use_copy_from_cache
  234. #define CD_DISPLAYED_SOME_DATA    cd->displayed_some_data
  235.  
  236. #define CE_URL_S            ce->URL_s
  237. #define CE_SOCK             ce->socket
  238. #define CE_CON_SOCK         ce->con_sock
  239. #define CE_STATUS           ce->status
  240. #define CE_WINDOW_ID        ce->window_id
  241. #define CE_BYTES_RECEIVED   ce->bytes_received
  242. #define CE_FORMAT_OUT       ce->format_out
  243.  
  244. /* forward decl */
  245. PRIVATE int32 net_ProcessHTTP (ActiveEntry *ce);
  246.  
  247. /*
  248.  * replace
  249.  *      return(CE_STATUS)
  250.  * with
  251.  *       RETURN_CE_STATUS
  252.  */
  253. PRIVATE
  254. int ReturnErrorStatus (int status)
  255. {
  256.     if (status < 0)
  257.         status |= status; /* set a breakpoint HERE to find errors */
  258.     return status;
  259. }
  260. #define STATUS(Status)            ReturnErrorStatus (Status)
  261.  
  262. #define PUTBLOCK(b, l)  (*cd->stream->put_block) \
  263.                                     (cd->stream, b, l)
  264. #define PUTSTRING(s)    (*cd->stream->put_block) \
  265.                                     (cd->stream, s, XP_STRLEN(s))
  266. #define COMPLETE_STREAM (*cd->stream->complete) \
  267.                                     (cd->stream)
  268. #define ABORT_STREAM(s) (*cd->stream->abort) \
  269.                                     (cd->stream, s)
  270. PUBLIC void
  271. NET_SetSendRefererHeader(Bool b)
  272. {
  273.     sendRefererHeader=b;
  274. }
  275.  
  276. /* set the method that the user wishes to identify themselves
  277.  * with.
  278.  * Default is DoNotIdentify unless this is called at startup
  279.  */
  280. PUBLIC void 
  281. NET_SetIdentifyMeType(IdentifyMeEnum method)
  282. {
  283.     http_identification_method = method;
  284. }
  285.  
  286. /* look for names like "ford" and "netscape"
  287.  * and turn them into "www.ford.com" and "www.netscape.com"
  288.  * If goBrowsing is enabled, this feature is turned off and the browser
  289.  * asks the search provider to resolve the word into a url. This is 
  290.  * is prevent a kid typing in bambi (looking for the deer) from being
  291.  * taken to a porn site.
  292.  * returns 0 if found and replaced
  293.  */
  294.  
  295. PRIVATE int
  296. net_check_for_company_hostname(ActiveEntry *ce)
  297. {
  298.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  299.     Bool add_www = FALSE;
  300.     Bool add_com = FALSE;
  301.     Bool goBrowsing = FALSE;
  302.    
  303.     if (PREF_GetBoolPref("browser.goBrowsingEnabled", &goBrowsing) != PREF_OK) goBrowsing = 0;
  304.  
  305.     if(!cd->orig_host)
  306.       {
  307.         char *dot=NULL;
  308.     
  309.         /* if the hostname doesn't have any
  310.          * dots in it, then assume it's of
  311.          * the form "netscape" or "ford".
  312.          * If we add www. and .com to the front
  313.          * and end we will get www.netscape.com :)
  314.          */
  315.         char * host = NET_ParseURL(CE_URL_S->address, GET_HOST_PART);
  316.     
  317.         if(host && *host && !(dot = XP_STRCHR(host, '.')))
  318.             {
  319.             add_www = add_com = TRUE;
  320.           }
  321.         else if(dot && !XP_STRCHR(dot+1, '.'))
  322.           {
  323.             /* there is only one dot in the host name
  324.              * so it's probably of the form of "netscape.com"
  325.              * or "ukans.edu".   Add a "www." on the front
  326.              * and try again.
  327.              */
  328.             add_www = TRUE;
  329.           }
  330.  
  331.         if(add_www) {
  332.           /* no dots in hostname */
  333.           if (goBrowsing && !XP_STRCHR(CE_URL_S->address, '/')) {            
  334.             char *pUrl;
  335.             PREF_CopyCharPref("network.search.url",&pUrl);
  336.             if (pUrl) {
  337.               char *tmp = NET_ParseURL(CE_URL_S->address, GET_HOST_PART);
  338.               char* new_address = PR_smprintf("%sgo+%s", pUrl, tmp);
  339.               XP_FREE(pUrl);
  340.               FREE(CE_URL_S->address);
  341.               FREEIF(tmp);  
  342.               CE_URL_S->address = new_address;
  343.     
  344.               if(cd->connection->sock != NULL)
  345.                 NET_TotalNumberOfOpenConnections--;
  346.               return (0);
  347.             } else return (-1);
  348.           } else {
  349.  
  350.             char *new_address = NET_ParseURL(CE_URL_S->address, 
  351.                                              GET_PROTOCOL_PART);
  352.             char *tmp = NET_ParseURL(CE_URL_S->address, GET_HOST_PART);
  353.  
  354.             /* save the host for error messages
  355.              */
  356.             cd->orig_host = tmp;
  357.     
  358.             StrAllocCat(new_address, "//www.");
  359.             StrAllocCat(new_address, tmp);
  360.     
  361.             if(add_com)
  362.                 StrAllocCat(new_address, ".com");
  363.  
  364.             tmp = NET_ParseURL(CE_URL_S->address, 
  365.                         GET_PATH_PART | GET_SEARCH_PART | GET_HASH_PART);
  366.                     
  367.             StrAllocCat(new_address, tmp);
  368.             FREEIF(tmp);
  369.     
  370.             FREE(CE_URL_S->address);
  371.             CE_URL_S->address = new_address;
  372.     
  373.             if(cd->connection->sock != NULL)
  374.                 NET_TotalNumberOfOpenConnections--;
  375.  
  376.             return(0);  /* will repeat this step */
  377.             }
  378.         }      
  379.       } 
  380.     else
  381.       {
  382.         /* the host mapping trick has already been applied and failed
  383.          * redo the error message and fail
  384.          */
  385.         CE_URL_S->error_msg = NET_ExplainErrorDetails(
  386.                                                 MK_UNABLE_TO_LOCATE_HOST, 
  387.                                                 cd->orig_host);
  388.                 /* fall through for failure case */
  389.       }
  390.  
  391.     return(-1);
  392. }
  393.  
  394. /* begins the connect process
  395.  *
  396.  * returns the TCP status code
  397.  */
  398. PRIVATE int
  399. net_start_http_connect(ActiveEntry * ce)
  400. {
  401.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  402.     Bool use_security=FALSE;
  403.     int def_port;
  404.  
  405.     def_port = DEF_HTTP_PORT;
  406.     if(ce->protocol == SECURE_HTTP_TYPE_URL)
  407.       {
  408.  
  409.         if(CD_PROXY_SERVER)
  410.           {
  411.             CD_USE_SSL_PROXY = TRUE;
  412.             CD_SSL_PROXY_SETUP_DONE = FALSE;
  413.  
  414.             TRACEMSG(("HTTP: Using SSL proxy"));
  415.  
  416.             /* put in code to check for using SSL to a proxy
  417.              * if we need to use ssl set the options
  418.              * on the next two lines
  419.              *
  420.              * use_security = TRUE;
  421.              * def_port = DEF_HTTPS_PORT;
  422.              * 
  423.              * @@@@@
  424.              */
  425.           }
  426.         else
  427.           {
  428.             use_security = TRUE;
  429.             def_port = DEF_HTTPS_PORT;
  430.           }
  431.       }
  432.  
  433.     /* if proxy_server is non NULL then use the string as a host:port
  434.      * when a proxy server is used a connection is made to the proxy
  435.      * host and port and the entire URL is sent instead of just
  436.      * the path part.
  437.      */ 
  438.     if(CD_PROXY_SERVER) 
  439.       {
  440.         /* MKConnect can take a URL or a host name as it's first
  441.           * argument
  442.           */
  443.         CE_STATUS = NET_BeginConnect (CD_PROXY_SERVER,  
  444.                                       NULL,
  445.                                       "HTTP", 
  446.                                       def_port, 
  447.                                       &cd->connection->sock, 
  448.                                       use_security, 
  449.                                       &CD_TCP_CON_DATA, 
  450.                                       CE_WINDOW_ID, 
  451.                                       &CE_URL_S->error_msg,
  452.                                       ce->socks_host,
  453.                                       ce->socks_port);
  454.       }
  455.     else
  456.       {
  457.         CE_STATUS = NET_BeginConnect (CE_URL_S->address,
  458.                                       CE_URL_S->IPAddressString,
  459.                                       "HTTP", 
  460.                                       def_port, 
  461.                                       &cd->connection->sock, 
  462.                                       use_security,  
  463.                                       &CD_TCP_CON_DATA, 
  464.                                       CE_WINDOW_ID, 
  465.                                       &CE_URL_S->error_msg,
  466.                                       ce->socks_host,
  467.                                       ce->socks_port);
  468.       }
  469.  
  470.     /* set this so mkgeturl can select on it */
  471.     CE_SOCK = cd->connection->sock;
  472.  
  473.     if(cd->connection->sock != NULL)
  474.         NET_TotalNumberOfOpenConnections++;
  475.  
  476.     if (CE_STATUS < 0) 
  477.       {
  478.         if(CE_STATUS == MK_UNABLE_TO_LOCATE_HOST 
  479.             && 0 == net_check_for_company_hostname(ce))
  480.           {
  481.             /* no need to set the state since this
  482.              * is the state we want again
  483.              */
  484.             if(cd->connection->sock != NULL)
  485.               {
  486.                 PR_Close(cd->connection->sock);
  487.                 cd->connection->sock = NULL;
  488.                 CE_SOCK = NULL;
  489.               }
  490.             return(0);
  491.           }
  492.  
  493.         TRACEMSG(("HTTP: Unable to connect to host for `%s' (errno = %d).", 
  494.                           CE_URL_S->address, SOCKET_ERRNO));
  495.         /*
  496.          * Proxy failover
  497.          */
  498.         if (CD_PROXY_CONF && CD_PROXY_SERVER &&
  499.             (CE_STATUS == MK_UNABLE_TO_CONNECT    ||
  500.              CE_STATUS == MK_CONNECTION_TIMED_OUT ||
  501.              CE_STATUS == MK_CONNECTION_REFUSED   ||
  502.              CE_STATUS == MK_UNABLE_TO_LOCATE_HOST))
  503.           {
  504. #ifdef MOZILLA_CLIENT
  505.               if (pacf_get_proxy_addr(CE_WINDOW_ID, CD_PROXY_CONF,
  506.                                       &ce->proxy_addr,
  507.                                       &ce->socks_host,
  508.                                       &ce->socks_port))
  509.                 {
  510.                     CD_PROXY_SERVER = ce->proxy_addr;
  511.                     return net_start_http_connect(ce);
  512.                 }
  513. #endif    /* MOZILLA_CLIENT */
  514.           }
  515.  
  516.         if(CE_STATUS == MK_UNABLE_TO_CONNECT && CD_PROXY_SERVER)
  517.           {
  518.             StrAllocCopy (CE_URL_S->error_msg,
  519.                           XP_GetString(MK_UNABLE_TO_CONNECT_TO_PROXY));
  520.             CE_STATUS = MK_UNABLE_TO_CONNECT_TO_PROXY;
  521.           }
  522.  
  523.         CD_NEXT_STATE = HTTP_ERROR_DONE;
  524.         return STATUS(CE_STATUS);
  525.       }
  526.  
  527.     if(CE_STATUS == MK_CONNECTED)
  528.       {
  529.         if(CD_USE_SSL_PROXY)
  530.             CD_NEXT_STATE = HTTP_SEND_SSL_PROXY_REQUEST;
  531.         else if(ce->URL_s->files_to_post)
  532.             CD_NEXT_STATE = HTTP_BEGIN_UPLOAD_FILE;
  533.         else
  534.           {
  535. HG56817
  536.                 CD_NEXT_STATE = HTTP_SEND_REQUEST;
  537.           }
  538.         TRACEMSG(("Connected to HTTP server on sock #%d",cd->connection->sock));
  539.         NET_SetReadSelect(CE_WINDOW_ID, cd->connection->sock);
  540.       }
  541.     else
  542.       {
  543.         CD_NEXT_STATE = HTTP_FINISH_CONNECT;
  544.         CD_PAUSE_FOR_READ = TRUE;
  545.         CE_CON_SOCK = cd->connection->sock;  /* set the socket for select */
  546.         NET_SetConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
  547.       }
  548.  
  549.     return STATUS(CE_STATUS);
  550. }
  551.  
  552. /*  begins the connect process
  553.  *
  554.  *  returns the TCP status code
  555.  */
  556. PRIVATE int
  557. net_finish_http_connect(ActiveEntry * ce)
  558. {
  559.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  560.     int def_port;
  561.  
  562.     def_port = DEF_HTTP_PORT;
  563.     if(ce->protocol == SECURE_HTTP_TYPE_URL)
  564.       {
  565.         def_port = DEF_HTTPS_PORT;
  566.       }
  567.  
  568.     /* if proxy_server is non NULL then use the string as a host:port
  569.      * when a proxy server is used a connection is made to the proxy
  570.      * host and port and the entire URL is sent instead of just
  571.      * the path part.
  572.      */
  573.     if(CD_PROXY_SERVER)
  574.       {
  575.         /* MKConnect can take a URL or a host name as it's first
  576.          * argument
  577.          */
  578.         CE_STATUS = NET_FinishConnect(CD_PROXY_SERVER,  
  579.                                       "HTTP",
  580.                                       def_port, 
  581.                                       &cd->connection->sock, 
  582.                                       &CD_TCP_CON_DATA, 
  583.                                       CE_WINDOW_ID,
  584.                                       &CE_URL_S->error_msg);
  585.       }
  586.     else
  587.       {
  588.         CE_STATUS = NET_FinishConnect(CE_URL_S->address,
  589.                                       "HTTP",
  590.                                       def_port,
  591.                                       &cd->connection->sock,  
  592.                                       &CD_TCP_CON_DATA, 
  593.                                       CE_WINDOW_ID,
  594.                                       &CE_URL_S->error_msg);
  595.       }
  596.  
  597.  
  598.     if (CE_STATUS < 0)
  599.       {
  600.         if(CE_STATUS == MK_UNABLE_TO_LOCATE_HOST 
  601.             && 0 == net_check_for_company_hostname(ce))
  602.           {
  603.             if(cd->connection->sock != NULL)
  604.               {
  605.                 NET_ClearConnectSelect(CE_WINDOW_ID, cd->connection->sock);
  606.                 PR_Close(cd->connection->sock);
  607.                 cd->connection->sock = NULL;
  608.                 CE_SOCK = NULL;
  609.                 CE_CON_SOCK = NULL;
  610.               }
  611.             cd->next_state = HTTP_START_CONNECT;
  612.               return(0);
  613.           }
  614.  
  615.         NET_ClearConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
  616.         TRACEMSG(("HTTP: Unable to connect to host for `%s' (errno = %d).",
  617.                                               CE_URL_S->address, SOCKET_ERRNO));
  618.  
  619.         /*
  620.          * Proxy failover
  621.          */
  622.         if (CD_PROXY_CONF && CD_PROXY_SERVER &&
  623.             (CE_STATUS == MK_UNABLE_TO_CONNECT    ||
  624.              CE_STATUS == MK_CONNECTION_TIMED_OUT ||
  625.              CE_STATUS == MK_CONNECTION_REFUSED   ||
  626.              CE_STATUS == MK_UNABLE_TO_LOCATE_HOST))
  627.           {
  628. #ifdef MOZILLA_CLIENT
  629.               if (pacf_get_proxy_addr(CE_WINDOW_ID, CD_PROXY_CONF,
  630.                                       &ce->proxy_addr,
  631.                                       &ce->socks_host,
  632.                                       &ce->socks_port))
  633.                 {
  634.                     CD_PROXY_SERVER = ce->proxy_addr;
  635.                     return net_start_http_connect(ce);
  636.                 }
  637. #endif    /* MOZILLA_CLIENT */
  638.           }
  639.  
  640.         /* proxy autodiscovery failover needs to be silent. If we were trying to
  641.          * connect to a pad server and failed, don't report errors, just go on
  642.          * about your business. */
  643.         if(NET_LoadingPac() && NET_UsingPadPac() ) {
  644.             /* Don't try to use the pad pac again. */
  645.             net_UsePadPac(FALSE);
  646.             CD_NEXT_STATE=HTTP_DONE;
  647.             CE_STATUS=0;
  648.             return STATUS(CE_STATUS);
  649.         }
  650.  
  651.         if(CE_STATUS == MK_UNABLE_TO_CONNECT && CD_PROXY_SERVER)
  652.           {
  653.             StrAllocCopy (CE_URL_S->error_msg,
  654.                           XP_GetString(MK_UNABLE_TO_CONNECT_TO_PROXY));
  655.             CE_STATUS = MK_UNABLE_TO_CONNECT_TO_PROXY;
  656.           }
  657.  
  658.         CD_NEXT_STATE = HTTP_ERROR_DONE;
  659.         return STATUS(CE_STATUS);
  660.       }
  661.  
  662.     if(CE_STATUS == MK_CONNECTED)
  663.       {
  664.         NET_ClearConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
  665.         CE_CON_SOCK = NULL;  /* reset the socket so we don't select on it  */
  666.         /* set this so mkgeturl can select on it */
  667.         CE_SOCK = cd->connection->sock;
  668.         if(CD_USE_SSL_PROXY)
  669.             CD_NEXT_STATE = HTTP_SEND_SSL_PROXY_REQUEST;
  670.         else if(ce->URL_s->files_to_post)
  671.             CD_NEXT_STATE = HTTP_BEGIN_UPLOAD_FILE;
  672.         else
  673.           {
  674. HG43241
  675.                 CD_NEXT_STATE = HTTP_SEND_REQUEST;
  676.           }
  677.         NET_SetReadSelect(CE_WINDOW_ID, cd->connection->sock);
  678.         TRACEMSG(("Connected to HTTP server on sock #%d",cd->connection->sock));
  679.  
  680.       } 
  681.     else
  682.       {
  683.         /* unregister the old CE_SOCK from the select list
  684.           * and register the new value in the case that it changes
  685.           */
  686.         if(ce->con_sock != cd->connection->sock)
  687.             {
  688.             NET_ClearConnectSelect(ce->window_id, ce->con_sock);
  689.             ce->con_sock = cd->connection->sock; 
  690.             NET_SetConnectSelect(ce->window_id, ce->con_sock);
  691.             }
  692.     
  693.         CD_PAUSE_FOR_READ = TRUE;
  694.       } 
  695.  
  696.     return STATUS(CE_STATUS);
  697. }
  698.  
  699. PRIVATE int
  700. net_send_ssl_proxy_request (ActiveEntry *ce)
  701. {
  702.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  703.     char *host = NET_ParseURL(CE_URL_S->address, GET_HOST_PART);
  704.     char *command=0;
  705.     char *auth = NULL;
  706.  
  707.     StrAllocCopy(command, "CONNECT ");
  708.     StrAllocCat(command, host);
  709.  
  710.     if(!XP_STRCHR(host, ':'))
  711.       {
  712.         char small_buf[20];
  713.         XP_SPRINTF(small_buf, ":%d", DEF_HTTPS_PORT);
  714.         StrAllocCat(command, small_buf);
  715.       }
  716.  
  717.     StrAllocCat(command, " "VERSION_STRING"\n");
  718.     
  719.     /*
  720.      * Check if proxy is requiring authorization.
  721.      * If NULL, not necessary, or the proxy will return 407 to
  722.      * require authorization.
  723.      *
  724.      */
  725.     if (NULL != (auth=NET_BuildProxyAuthString(CE_WINDOW_ID,
  726.                                                CE_URL_S,
  727.                                                CD_PROXY_SERVER)))
  728.       {
  729.           char *line = (char *)XP_ALLOC(strlen(auth) + 30);
  730.           if (line) {
  731.               XP_SPRINTF(line, "Proxy-authorization: %s%c%c", auth, CR, LF);
  732.               StrAllocCat(command, line);
  733.               XP_FREE(line);
  734.           }
  735.           CD_SENT_PROXY_AUTH = TRUE;
  736.           TRACEMSG(("HTTP: Sending proxy-authorization: %s", auth));
  737.       }
  738.     else
  739.       {
  740.           TRACEMSG(("HTTP: Not sending proxy authorization (yet)"));
  741.       }
  742.  
  743.     {
  744.         char line[200];
  745.         XP_SPRINTF(line, "User-Agent: %.100s/%.90s" CRLF CRLF,
  746.                    XP_AppCodeName, XP_AppVersion);
  747.         StrAllocCat(command, line);
  748.     }
  749.  
  750.     TRACEMSG(("Tx: %s", command));
  751.  
  752.     SSL_SetSockPeerID(cd->connection->sock, command);
  753.     CE_STATUS = NET_HTTPNetWrite(cd->connection->sock, command, XP_STRLEN(command));
  754.  
  755.     FREE(command);
  756.  
  757.     CD_PAUSE_FOR_READ = TRUE;
  758.  
  759.     CD_NEXT_STATE = HTTP_PARSE_FIRST_LINE;
  760.  
  761.     return(CE_STATUS);
  762. }
  763.  
  764. #define POST_DATA_BUFFER_SIZE 2048
  765.  
  766. PRIVATE int32
  767. net_get_size_with_crlf( char *filename, XP_FileType file_type, XP_Bool add_crlf )
  768. {
  769.     XP_File xpfileptr;
  770.     uint32 return_value = 0;
  771.     int line_length;
  772.     char *line;
  773.     char *buffer;
  774.     
  775.     if (!add_crlf)
  776.     {
  777.         /* Don't need to make any cr/lf adjustment, just stat the file and
  778.            return the size. */
  779.         
  780.         XP_StatStruct stat_entry;
  781.         if(-1 == XP_Stat(filename, &stat_entry, file_type))
  782.             return -1;
  783.         else
  784.             return stat_entry.st_size;
  785.     }
  786.     
  787.     xpfileptr = XP_FileOpen( filename, file_type, XP_FILE_READ );
  788.     if (!xpfileptr)
  789.         return -1;
  790.     
  791.     buffer = (char *) XP_ALLOC(POST_DATA_BUFFER_SIZE);
  792.     if (!buffer)
  793.         return -1;
  794.     
  795.     do {
  796.       line = XP_FileReadLine(buffer, POST_DATA_BUFFER_SIZE-5, xpfileptr);
  797.       if (!line)
  798.         break;
  799.  
  800.       line_length = XP_STRLEN(line);
  801.  
  802.       if (line_length > 1 && line[line_length-2] == CR && line[line_length-1] == LF)
  803.          {
  804.             /* already ok */
  805.         }
  806.       else if(line_length > 0 && (line[line_length-1] == LF || line[line_length-1] == CR))
  807.         {
  808.               /* increment to account for missing CR or missing LF */
  809.               line_length++;
  810.         }
  811.  
  812.       return_value += line_length;
  813.     } while (line);
  814.  
  815.     XP_FREE( buffer );
  816.     
  817.     return return_value;
  818. }
  819.  
  820. /* begin sending a file
  821.  */
  822. PRIVATE int
  823. net_begin_upload_file (ActiveEntry *ce)
  824. {
  825.     HTTPConData * cd = (HTTPConData *) ce->con_data;
  826.     char * filename;
  827.     char * file_to_post;
  828.     char * header=0;
  829.     char * last_slash;
  830.     char * status_msg;
  831.     int i;
  832.     int32 adjusted_file_size = -1;
  833.  
  834.     if(ce->URL_s->server_status == 401)
  835.       {
  836.         /* retrying with auth, don't change the filename */
  837.         cd->next_state = HTTP_SEND_REQUEST;
  838.         return(0);
  839.       }
  840.  
  841.     XP_ASSERT(ce->URL_s->files_to_post && ce->URL_s->files_to_post[0]);
  842.     if(!ce->URL_s->files_to_post || !ce->URL_s->files_to_post[0])
  843.         return MK_UNABLE_TO_LOCATE_FILE;
  844.  
  845.     /* get a filename from the files_to_post array
  846.      */
  847.     for(i=0; ce->URL_s->files_to_post[i]; i++)
  848.         ; /* find the end */
  849.  
  850.     XP_ASSERT(i>0);
  851.  
  852.     file_to_post = ce->URL_s->files_to_post[i-1];
  853.  
  854.     /* zero the file now so that we don't upload it again. */
  855.     ce->URL_s->files_to_post[i-1] = NULL;
  856.  
  857. #ifdef XP_MAC
  858.     filename = XP_STRRCHR(file_to_post, '/');
  859. #elif defined(XP_WIN)
  860.     filename = XP_STRRCHR(file_to_post, '\\');
  861. #else
  862.     filename = XP_STRRCHR(file_to_post, '/');
  863. #endif
  864.  
  865.     if(!filename)
  866.         filename = file_to_post;
  867.     else
  868.         filename++; /* go past delimiter */
  869.  
  870.     /* get the size of the file adjusting for crlf conversion */
  871.     adjusted_file_size = net_get_size_with_crlf(file_to_post, xpFileToPost, ce->URL_s->add_crlf ? ce->URL_s->add_crlf[i-1] : FALSE);
  872.     if (-1 == adjusted_file_size)
  873.       {                                                                                           
  874.         ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_LOCATE_FILE, file_to_post);
  875.         FREE(file_to_post);
  876.         return MK_UNABLE_TO_LOCATE_FILE;
  877.       }
  878.         
  879.     status_msg = PR_smprintf("Uploading file %s", filename);
  880.     if(status_msg)
  881.       {
  882.         NET_Progress(ce->window_id, status_msg);
  883.         FREE(status_msg);
  884.       }        
  885.  
  886. /*#ifdef EDITOR
  887.    FE_SaveDialogSetFilename(ce->window_id, filename);
  888. #endif */  /* EDITOR */
  889.  
  890.     header = PR_smprintf("Content-Length: %ld" CRLF CRLF, adjusted_file_size);
  891.  
  892.  
  893.     FREEIF(ce->URL_s->post_headers);
  894.     /* if header is null this won't crash */
  895.     ce->URL_s->post_headers = header;
  896.  
  897.     /* If the destination URL is explicitly specified in the post_to array, use it, otherwise
  898.      * generate destination from URL_s->address and filename.  hardts */
  899.     if (ce->URL_s->post_to && ce->URL_s->post_to[i - 1]) {
  900.         XP_FREE(ce->URL_s->address); /* We don't use it at all. */
  901.         ce->URL_s->address = ce->URL_s->post_to[i - 1];
  902.         ce->URL_s->post_to[i - 1] = NULL;  /* zero the element */
  903.     }
  904.     else {
  905.          /* strip the filename from the last slash and append the
  906.          * new filename to the URL
  907.          */
  908.         last_slash = XP_STRRCHR(ce->URL_s->address, '/');
  909.         if(last_slash)
  910.             *last_slash = '\0';
  911.         StrAllocCat(ce->URL_s->address, "/");
  912.         StrAllocCat(ce->URL_s->address, filename);
  913.     }
  914.  
  915. #ifdef EDITOR
  916.     {
  917.          /* Strip out username and password. from address */
  918.         char *pLocation = NULL;
  919.         if (!NET_ParseUploadURL( ce->URL_s->address, &pLocation, NULL,NULL )) {
  920.             XP_ASSERT(0);
  921.         }        
  922.         if (CLEAR_CACHE_BIT(ce->format_out) != FO_LOCATION_INDEPENDENCE)
  923.             FE_SaveDialogSetFilename(ce->window_id, pLocation);
  924.         XP_FREE(pLocation);
  925.    }
  926. #endif /* EDITOR */
  927.  
  928.     /* make the method PUT */
  929.     ce->URL_s->method = URL_PUT_METHOD;
  930.  
  931.     /* specify the file to be uploaded */
  932.     StrAllocCopy(ce->URL_s->post_data, file_to_post);
  933.  
  934.     /* specify that the post data is a file */
  935.     ce->URL_s->post_data_is_file = TRUE;
  936.  
  937.     /* do the request */
  938.     cd->next_state = HTTP_SEND_REQUEST;
  939.     
  940.     FREE(file_to_post);
  941.  
  942.     return(0);
  943. }
  944.  
  945. /* build the HTTP request.
  946.  *
  947.  * mallocs a big string that must be free'd
  948.  * returns the string
  949.  */
  950. PRIVATE unsigned int
  951. net_build_http_request (URL_Struct * URL_s,
  952.                         FO_Present_Types format_out,
  953.                         Bool          http1, 
  954.                         char           * proxy_server, 
  955.                         Bool          posting, 
  956.                         MWContext      * window_id,
  957.                         char          ** command,
  958.                         Bool        * sent_authorization,
  959.                         Bool        * sent_proxy_auth)
  960. {
  961.     char line_buffer[4096];  /* buffer */
  962.     char *auth;         /* authorization header string */
  963.     size_t csize;        /* size of command */
  964.     const char *tempURL=NULL;
  965.     char *proxyServer=NULL;
  966.         
  967.     /* begin the request
  968.      */
  969.     switch(URL_s->method)
  970.       {
  971.         case URL_MKDIR_METHOD:
  972. #define MKDIR_WORD "MKDIR "
  973.             BlockAllocCopy(*command, MKDIR_WORD, 5);
  974.             csize = sizeof(MKDIR_WORD)-1;
  975.             break;
  976.  
  977.         case URL_DELETE_METHOD:
  978. #define DELETE_WORD "DELETE "
  979. #define RMDIR_WORD "RMDIR "
  980.             if(URL_s->is_directory)
  981.               {
  982.                 BlockAllocCopy(*command, RMDIR_WORD, 6);
  983.                 csize = sizeof(RMDIR_WORD)-1;
  984.               }
  985.             else
  986.               {
  987.                 BlockAllocCopy(*command, DELETE_WORD, 7);
  988.                 csize = sizeof(DELETE_WORD)-1;
  989.               }
  990.             break;
  991.  
  992.         case URL_POST_METHOD:
  993. #define POST_WORD "POST "
  994.             BlockAllocCopy(*command, POST_WORD, 5);
  995.             csize = sizeof(POST_WORD)-1;
  996.             break;
  997.  
  998.         case URL_PUT_METHOD:
  999. #define PUT_WORD "PUT "
  1000.             BlockAllocCopy(*command, PUT_WORD, 4);
  1001.             csize = sizeof(PUT_WORD)-1;
  1002.             break;
  1003.  
  1004.         case URL_HEAD_METHOD:
  1005. #define HEAD_WORD "HEAD "
  1006.             BlockAllocCopy(*command, HEAD_WORD, 5);
  1007.             csize = sizeof(HEAD_WORD)-1;
  1008.             break;
  1009.             
  1010.         case URL_INDEX_METHOD:
  1011. #define INDEX_WORD "INDEX "
  1012.             BlockAllocCopy(*command, INDEX_WORD, 6);
  1013.             csize = sizeof(INDEX_WORD)-1;
  1014.             break;
  1015.  
  1016.         case URL_MOVE_METHOD:
  1017. #define MOVE_WORD "MOVE "
  1018.             BlockAllocCopy(*command, MOVE_WORD, 5);
  1019.             csize = sizeof(MOVE_WORD)-1;
  1020.             break;
  1021.  
  1022.         case URL_COPY_METHOD:
  1023. #define COPY_WORD "COPY "
  1024.             BlockAllocCopy(*command, COPY_WORD, 5);
  1025.             csize = sizeof(COPY_WORD)-1;
  1026.             break;
  1027.  
  1028.         default:
  1029.             XP_ASSERT(0);
  1030.             /* fall through to GET */
  1031.  
  1032.         case URL_GET_METHOD:
  1033. #define GET_WORD "GET "
  1034.             BlockAllocCopy(*command, GET_WORD, 4);
  1035.             csize = sizeof(GET_WORD)-1;
  1036.             break;
  1037.  
  1038.         case URL_GETPROPERTIES_METHOD:
  1039. #define GETPROPERTIES_WORD "GETPROPERTIES "
  1040.             BlockAllocCopy(*command, GETPROPERTIES_WORD, 14);
  1041.             csize = sizeof(GETPROPERTIES_WORD)-1;
  1042.             break;
  1043.       }
  1044.  
  1045.  
  1046.     /* if we are using a proxy gateway copy in the entire URL
  1047.      * minus the hash mark
  1048.      */
  1049.     if(proxy_server)
  1050.       {
  1051.  
  1052.         char *url_minus_hash = NET_ParseURL(URL_s->address, 
  1053.             GET_PROTOCOL_PART 
  1054.             | GET_USERNAME_PART
  1055.             | GET_PASSWORD_PART
  1056.             | GET_HOST_PART 
  1057.             | GET_PATH_PART 
  1058.             | GET_SEARCH_PART);
  1059.         if(url_minus_hash)
  1060.         {
  1061.             BlockAllocCat(*command, (size_t) csize, url_minus_hash, XP_STRLEN(url_minus_hash));
  1062.             csize += XP_STRLEN(url_minus_hash);
  1063.             XP_FREE(url_minus_hash);
  1064.         }
  1065.  
  1066.       }
  1067.     else 
  1068.       {
  1069.         /* else use just the path and search stuff
  1070.          */
  1071.         char *path = NET_ParseURL(URL_s->address, 
  1072.                                         GET_PATH_PART | GET_SEARCH_PART);
  1073.         BlockAllocCat(*command, csize, path, XP_STRLEN(path));
  1074.         csize += XP_STRLEN(path);
  1075.  
  1076.         XP_FREE(path);
  1077.       }
  1078.  
  1079.     if(http1) 
  1080.       {
  1081.         BlockAllocCat(*command, csize, " ", 1);
  1082.         csize += 1;
  1083.         BlockAllocCat(*command, csize, 
  1084.                       VERSION_STRING, 
  1085.                       XP_STRLEN(VERSION_STRING));
  1086.         csize += XP_STRLEN(VERSION_STRING);
  1087.         /* finish the line */
  1088.         BlockAllocCat(*command, csize, CRLF, 2); /* CR LF, as in rfc 977 */
  1089.         csize += 2;
  1090.  
  1091.         if ((URL_s->etag) && (URL_s->force_reload != NET_SUPER_RELOAD))
  1092.         {
  1093.             /* add the If-None-Match header */
  1094.             XP_STRCPY(line_buffer, "If-None-Match: \"");
  1095.             BlockAllocCat(*command, csize,
  1096.                 line_buffer, XP_STRLEN(line_buffer));
  1097.             csize += XP_STRLEN(line_buffer);
  1098.             BlockAllocCat(*command, csize, 
  1099.                 URL_s->etag,
  1100.                 XP_STRLEN(URL_s->etag));
  1101.             csize += XP_STRLEN(URL_s->etag);
  1102.             /* Closing " */
  1103.             BlockAllocCat(*command, csize,
  1104.                 "\"",
  1105.                 1);
  1106.             csize += 1;
  1107.             BlockAllocCat(*command, csize, CRLF, 2);
  1108.             csize += 2;
  1109.         }
  1110.  
  1111.         if(URL_s->last_modified && URL_s->force_reload != NET_SUPER_RELOAD)
  1112.           {
  1113.             /* add if modified since
  1114.              *
  1115.              * right now this is being added even if the server sent pragma: no-cache
  1116.              * I'm not sure if this is the right thing to do but it seems
  1117.              * very efficient since we can still use the cache.
  1118.              */
  1119.  
  1120.         /* add tmp character storage for strings in order for assert
  1121.              * to work properly in debug compile.
  1122.              * IBM compiler does not put "\" to make " work properly.
  1123.              */
  1124. #ifndef AIX
  1125.             char *tmp_str = "http";
  1126. #endif
  1127.             {
  1128.                /* A conversion from time_t to NSPR's int64 is needed in order to
  1129.                 * use the NSPR time functions.  URL_Struct should really be changed
  1130.                 * to use the NSPR time type instead of time_t.
  1131.                 */
  1132. #ifndef NSPR20
  1133.                uint64   timeInSec;
  1134.                uint64    timeInUSec;
  1135.                uint64   secToUSec;
  1136.                PRTime    expandedTime;
  1137. #else
  1138.                PRTime   timeInSec;
  1139.                PRTime    timeInUSec;
  1140.                PRTime   secToUSec;
  1141.                PRExplodedTime    expandedTime;
  1142. #endif /* NSPR20 */
  1143.  
  1144.                LL_I2L(timeInSec, URL_s->last_modified);
  1145.                LL_I2L(secToUSec, PR_USEC_PER_SEC);
  1146.                LL_MUL(timeInUSec, timeInSec, secToUSec);
  1147. #ifndef NSPR20
  1148. #ifndef XP_MAC
  1149.                timeInUSec = PR_ToGMT(timeInUSec);
  1150. #endif /* XP_MAC */
  1151.                PR_ExplodeTime(&expandedTime, timeInUSec);
  1152. #else
  1153.                PR_ExplodeTime(timeInUSec, PR_GMTParameters, &expandedTime);
  1154. #endif /* NSPR20 */
  1155.                PR_FormatTimeUSEnglish(line_buffer, 400,
  1156.                                       "If-Modified-Since: %a, %d %b %Y %H:%M:%S GMT",
  1157.                                       &expandedTime);
  1158.             }
  1159.  
  1160.             /* must not be zero for http URL's 
  1161.              * or else I screwed up the cache logic 
  1162.              */
  1163. #ifndef AIX
  1164.             XP_ASSERT(strncasecomp(URL_s->address, tmp_str, 4)
  1165.                       || URL_s->real_content_length > 0);
  1166. #endif
  1167.  
  1168.             if(URL_s->real_content_length)
  1169.                 XP_SPRINTF(&line_buffer[XP_STRLEN(line_buffer)], 
  1170.                             "; length=%ld" CRLF,
  1171.                             URL_s->real_content_length);
  1172.             BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1173.             csize += XP_STRLEN(line_buffer);
  1174.  
  1175.             /* reset the expires since we will want to
  1176.              * either get a new one from the server or
  1177.              * set it to zero
  1178.              */
  1179.             URL_s->expires = 0;
  1180.           }
  1181.  
  1182.         if(URL_s->http_headers)  /* use headers that were passed in */
  1183.           {
  1184.  
  1185.             BlockAllocCat(*command, csize, URL_s->http_headers, XP_STRLEN(URL_s->http_headers));
  1186.             csize += XP_STRLEN(URL_s->http_headers);
  1187.           }
  1188.         else
  1189.           {
  1190.             /* For MOVE method. This contains the destination uri name */
  1191.             int meth=URL_s->method;
  1192.             if(URL_s->destination 
  1193.                 && (*(URL_s->destination) != '\0')
  1194.                 && ( (meth == URL_MOVE_METHOD)
  1195.                         || (meth == URL_COPY_METHOD) ) 
  1196.                 ){
  1197.                 int len=0;
  1198.                 if(meth == URL_MOVE_METHOD) {
  1199.                     XP_SPRINTF(line_buffer, "New-uri: %s", URL_s->destination);
  1200.                     len=XP_STRLEN(line_buffer);
  1201.                     BlockAllocCat(*command, csize, line_buffer, len);
  1202.                     csize+=len;
  1203.                 }
  1204.                 else if(meth == URL_COPY_METHOD) {
  1205.                     ;/* some http copy syntax */
  1206.                 }
  1207.  
  1208.                 BlockAllocCat(*command, csize, CRLF, XP_STRLEN(CRLF));
  1209.                 csize += XP_STRLEN(CRLF);
  1210.             }
  1211.             /* sendRefererHeader is set in NET_SetSendRefererHeaderPref in mkhttp.c. 
  1212.                This condition is set via a javascript pref and was implemented to 
  1213.                settle some privacy/security issue */
  1214.             if(sendRefererHeader)
  1215.             {
  1216.                 int url_type = NET_URL_Type(URL_s->referer);
  1217.                 if(URL_s->referer 
  1218.                     && url_type != MAILBOX_TYPE_URL
  1219.                     && url_type != IMAP_TYPE_URL
  1220.                     && url_type != FILE_TYPE_URL)
  1221.                   {
  1222.                     TRACEMSG(("Sending referer field"));
  1223.                     XP_STRCPY(line_buffer, "Referer: ");
  1224.                     BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1225.                     csize += XP_STRLEN(line_buffer);
  1226.                     BlockAllocCat(*command,  csize, URL_s->referer,
  1227.                                   XP_STRLEN(URL_s->referer));
  1228.                     csize += XP_STRLEN(URL_s->referer);
  1229.                     BlockAllocCat(*command, csize, CRLF, 2);
  1230.                     csize += 2;
  1231.                   }
  1232.             }
  1233.  
  1234.             assert (XP_AppCodeName);
  1235.             assert (XP_AppVersion);
  1236.  
  1237.             if(proxy_server)
  1238.                 XP_STRCPY(line_buffer, "Proxy-Connection: Keep-Alive" CRLF);
  1239.             else
  1240.                 XP_STRCPY(line_buffer, "Connection: Keep-Alive" CRLF);
  1241.  
  1242.             XP_SPRINTF (&line_buffer[XP_STRLEN(line_buffer)], 
  1243.                         "User-Agent: %.100s/%.90s" CRLF,
  1244.                         XP_AppCodeName, XP_AppVersion);
  1245.             BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1246.             csize += XP_STRLEN(line_buffer);
  1247.  
  1248.             if(URL_s->force_reload)
  1249.               {
  1250.                 BlockAllocCat(*command, csize, "Pragma: no-cache" CRLF, 18);
  1251.                 csize += 18;
  1252.               }
  1253.  
  1254.             if(URL_s->range_header)
  1255.               {
  1256. #ifndef AIX
  1257.                 char *tmp_str = CRLF;
  1258.                 XP_ASSERT(!XP_STRSTR(URL_s->range_header, tmp_str));
  1259. #endif
  1260. #define REQUEST_RANGE_HEADER "Range: "
  1261.                 BlockAllocCat(*command, csize, 
  1262.                               REQUEST_RANGE_HEADER,
  1263.                               XP_STRLEN(REQUEST_RANGE_HEADER));
  1264.                 csize += XP_STRLEN(REQUEST_RANGE_HEADER);
  1265.                 BlockAllocCat(*command, csize, 
  1266.                               URL_s->range_header,
  1267.                               XP_STRLEN(URL_s->range_header));
  1268.                 csize += XP_STRLEN(URL_s->range_header);
  1269.                 BlockAllocCat(*command, csize, 
  1270.                               CRLF, XP_STRLEN(CRLF));
  1271.                 csize += XP_STRLEN(CRLF);
  1272.               }
  1273.  
  1274. #define OLD_RANGE_SUPPORT
  1275. #ifdef OLD_RANGE_SUPPORT
  1276.             /* this is here for backwards compatibility with
  1277.              * the old range spec
  1278.              * It should be removed before final beta 2
  1279.              */
  1280.             if(URL_s->range_header)
  1281.               {
  1282. #ifndef AIX
  1283.         char *tmp_str = CRLF;
  1284.                 XP_ASSERT(!XP_STRSTR(URL_s->range_header, tmp_str));
  1285. #endif
  1286. #undef REQUEST_RANGE_HEADER
  1287. #define REQUEST_RANGE_HEADER "Request-Range: "
  1288.                 BlockAllocCat(*command, csize,
  1289.                               REQUEST_RANGE_HEADER,
  1290.                               XP_STRLEN(REQUEST_RANGE_HEADER));
  1291.                 csize += XP_STRLEN(REQUEST_RANGE_HEADER);
  1292.                 BlockAllocCat(*command, csize,
  1293.                               URL_s->range_header,
  1294.                               XP_STRLEN(URL_s->range_header));
  1295.                 csize += XP_STRLEN(URL_s->range_header);
  1296.                 BlockAllocCat(*command, csize,
  1297.                               CRLF, XP_STRLEN(CRLF));
  1298.                 csize += XP_STRLEN(CRLF);
  1299.               }
  1300. #endif
  1301.  
  1302.             if(1)
  1303.               {
  1304.                 char * host = NET_ParseURL(URL_s->address, GET_HOST_PART);
  1305.  
  1306.                 if(host)
  1307.                   {
  1308.                     int len;
  1309.  
  1310. #define HOST_HEADER "Host: "
  1311.                     BlockAllocCat(*command, 
  1312.                                     csize,     
  1313.                                     HOST_HEADER,     
  1314.                                     sizeof(HOST_HEADER)-1);
  1315.                     csize += sizeof(HOST_HEADER)-1;
  1316.                     len = XP_STRLEN(host);
  1317.                     BlockAllocCat(*command, csize, host, len);
  1318.     
  1319.                     csize += len;
  1320.  
  1321.                     FREE(host);
  1322.  
  1323.                     BlockAllocCat(*command, csize, CRLF, 2);
  1324.                     csize += 2;
  1325.                   }
  1326.               }
  1327.  
  1328. #ifdef SEND_FROM_FIELD
  1329.             XP_SPRINTF(line_buffer, "From: %.256s%c%c", 
  1330.                             FE_UsersMailAddress() ? FE_UsersMailAddress() : "unregistered", CR,LF);
  1331.             BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1332.             csize += XP_STRLEN(line_buffer);
  1333. #endif /* SEND_FROM_FIELD */
  1334.  
  1335.  
  1336.             if(CLEAR_CACHE_BIT(format_out) != FO_INTERNAL_IMAGE)
  1337.               {
  1338.                 /* send Accept: *(slash)* as well as the others
  1339.                  */
  1340.                 XP_SPRINTF(line_buffer, "Accept: %s, %s, %s, %s, %s, */*" CRLF, 
  1341.                             IMAGE_GIF, IMAGE_XBM, IMAGE_JPG, IMAGE_PJPG, IMAGE_PNG);
  1342.               }
  1343.             else
  1344.               {
  1345.                 XP_SPRINTF(line_buffer, "Accept: %s, %s, %s, %s, %s" CRLF, 
  1346.                             IMAGE_GIF, IMAGE_XBM, IMAGE_JPG, IMAGE_PJPG, IMAGE_PNG);
  1347.               }
  1348.  
  1349.             BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1350.             csize += XP_STRLEN(line_buffer);
  1351.  
  1352.             /* add Accept-Encoding Header */
  1353.             XP_SPRINTF(line_buffer, "Accept-Encoding: %s" CRLF, ENCODING_GZIP2);
  1354.             BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1355.             csize += XP_STRLEN(line_buffer);
  1356.  
  1357. #ifdef MOZILLA_CLIENT
  1358. #define SEND_ACCEPT_LANGUAGE 1
  1359. #ifdef SEND_ACCEPT_LANGUAGE    /* Added by ftang */
  1360.             {
  1361.                 char *acceptlang = INTL_GetAcceptLanguage();
  1362.                 if((acceptlang != NULL) && ( *acceptlang != '\0') )
  1363.                 {
  1364.                     XP_SPRINTF(line_buffer, "Accept-Language: %s" CRLF, 
  1365.                                    acceptlang );
  1366.                     BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1367.                     csize += XP_STRLEN(line_buffer);
  1368.                 }
  1369.             }
  1370. #endif /* SEND_ACCEPT_LANGUAGE */
  1371.  
  1372. #define SEND_ACCEPT_CHARSET 1
  1373. #ifdef SEND_ACCEPT_CHARSET    /* Added by bstell */
  1374.             {
  1375.                 char *acceptCharset = INTL_GetAcceptCharset();
  1376.                 if((acceptCharset != NULL) && ( *acceptCharset != '\0') )
  1377.                 {
  1378.                     XP_SPRINTF(line_buffer, "Accept-Charset: %s" CRLF, 
  1379.                                    acceptCharset );
  1380.                     BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1381.                     csize += XP_STRLEN(line_buffer);
  1382.                 }
  1383.             }
  1384. #endif /* SEND_ACCEPT_CHARSET */
  1385. #endif /* MOZILLA_CLIENT */
  1386.  
  1387.             /*
  1388.              * Check if proxy is requiring authorization.
  1389.              * If NULL, not necessary, or the proxy will return 407 to
  1390.              * require authorization.
  1391.              *
  1392.             */
  1393.             /* This was hacked in because proxy auth can be required when the Auto-config url
  1394.              * itself requires authorization. We used to ask for proxy auth only when the proxy was 
  1395.              * input directly into the prefs. Now we check to see if there's a pacurl (if there
  1396.              * is, there can't be a proxy url simultaneously) use it, otherwise we're using a
  1397.              * proxy from the prefs.
  1398.              */
  1399.     
  1400.             /* Figure out which kind of proxy we're using: PAC or straight proxy. 
  1401.              * DON'T FREE tempURL!!!
  1402.              */
  1403.             if ( (tempURL = net_GetPACUrl()) && (*tempURL) )
  1404.                 proxyServer = NET_ParseURL(tempURL, GET_HOST_PART | GET_PATH_PART | GET_USERNAME_PART | GET_PASSWORD_PART);
  1405.             else 
  1406.                 proxyServer = proxy_server; 
  1407.  
  1408.             if (proxyServer &&
  1409.                 NULL != (auth=NET_BuildProxyAuthString(window_id,
  1410.                                                        URL_s,
  1411.                                                        proxyServer)))
  1412.               {
  1413.                 if (tempURL)
  1414.                     XP_FREE(proxyServer);
  1415.                 *sent_proxy_auth = TRUE;
  1416.                 XP_SPRINTF(line_buffer, "Proxy-authorization: %.3840s%c%c", auth, CR, LF);
  1417.                 BlockAllocCat(*command, csize, line_buffer, XP_STRLEN(line_buffer));
  1418.                 csize += XP_STRLEN(line_buffer);
  1419.                 TRACEMSG(("HTTP: Sending proxy-authorization: %s", auth));
  1420.               }
  1421.             else 
  1422.               {
  1423.                 TRACEMSG(("HTTP: Not sending proxy authorization (yet)"));
  1424.               }
  1425.  
  1426.             /* NET_BuildAuthString will return non-NULL if authorization is
  1427.              * known to be required for this document.
  1428.              *
  1429.              * If NULL is returned authorization is not required or is
  1430.              * not known to be required yet so we will look for a 401
  1431.              * return code later on to see if authorization will be
  1432.              * neccessary
  1433.              */
  1434.             if (NULL!=(auth=NET_BuildAuthString(window_id, URL_s))) 
  1435.               {
  1436.                 *sent_authorization = TRUE;
  1437.                 BlockAllocCat(*command, csize, auth, XP_STRLEN(auth));
  1438.                 csize += XP_STRLEN(auth);
  1439.                 TRACEMSG(("HTTP: Sending authorization: %s", auth));
  1440.               }
  1441.             else 
  1442.               {
  1443.                 TRACEMSG(("HTTP: Not sending authorization (yet)"));
  1444.               }
  1445.  
  1446.             if (NULL!=(auth=NET_GetCookie(window_id, URL_s->address))) 
  1447.               {
  1448.                 int len;
  1449.                 XP_STRCPY(line_buffer, "Cookie: ");
  1450.                 BlockAllocCat(*command, csize, 
  1451.                               line_buffer, XP_STRLEN(line_buffer));
  1452.                 
  1453.                 csize += XP_STRLEN(line_buffer);
  1454.                 len = XP_STRLEN(auth);
  1455.                 BlockAllocCat(*command, csize, auth, len);
  1456.                 csize += len;
  1457.                 BlockAllocCat(*command, csize, CRLF, XP_STRLEN(CRLF));
  1458.                 csize += XP_STRLEN(CRLF);
  1459.                 TRACEMSG(("HTTP: Sending Cookie: %s", auth));
  1460.         XP_FREE(auth);
  1461.               }
  1462.             else
  1463.               {
  1464.                 TRACEMSG(("HTTP: Not sending cookie"));
  1465.               }
  1466.  
  1467.           }  /* end of if passed in headers */
  1468.       }  /* end of if(http1) */
  1469.  
  1470.     /* end of Get/Post request */
  1471.  
  1472.     /* Blank line means "end" of headers
  1473.      * If we are posting WritePostData will
  1474.      * add the extra line feed for us
  1475.      */
  1476.     if(!posting)
  1477.       {
  1478.         BlockAllocCat(*command, csize, CRLF, 2); 
  1479.         csize += 2;
  1480.       }
  1481.  
  1482.     return((unsigned int) csize);
  1483. }
  1484.  
  1485. HG12515
  1486.  
  1487. /* send_http_request  makes a connection to the http server
  1488.  * and sends a request (ethier http1 or http/.9) to the server
  1489.  *
  1490.  * returns the TCP status code
  1491.  */
  1492. #define SOCK_CHUNK_SIZE 1024
  1493. PRIVATE int
  1494. net_send_http_request (ActiveEntry *ce)
  1495. {
  1496.     /* assign it so that we have a typed structure pointer */
  1497.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  1498.     char * command=0;
  1499.     unsigned int  command_size;
  1500.  
  1501.     /* we make the assumption that we are always acting as a proxy
  1502.      * server if we get http_headers passed in the URL structure.
  1503.      *
  1504.      * when acting as a proxy_server the clients headers are sent
  1505.      * to the server instead of being generated here and the headers
  1506.      * from the server are unparsed and sent on the the client.
  1507.      */
  1508.     if(ce->format_out == FO_OUT_TO_PROXY_CLIENT ||
  1509.             ce->format_out == FO_CACHE_AND_OUT_TO_PROXY_CLIENT)
  1510.         CD_ACTING_AS_PROXY=YES;
  1511.  
  1512.     TRACEMSG(("Entered \"send_http_request\""));
  1513.  
  1514.     /* we make the assumption that we will always use the POST
  1515.      * method if there is post data in the URL structure
  1516.      * Is that a bad assumption?
  1517.      */
  1518.     if(CE_URL_S->method == URL_POST_METHOD
  1519.         || CE_URL_S->method == URL_PUT_METHOD) {
  1520.         CD_POSTING = YES;
  1521. #ifdef MOZILLA_CLIENT
  1522.         SECNAV_Posting(cd->connection->sock);
  1523. #endif /* MOZILLA_CLIENT */
  1524.     } else if (CE_URL_S->method == URL_HEAD_METHOD) {
  1525. #ifdef MOZILLA_CLIENT
  1526.         SECNAV_HTTPHead(cd->connection->sock);
  1527. #endif /* MOZILLA_CLIENT */
  1528.     }
  1529.     
  1530.     /* zero out associated mime fields in URL structure
  1531.      *
  1532.       * all except content_length since that may be passed in
  1533.      */
  1534.     CE_URL_S->protection_template = 0;
  1535.     FREE_AND_CLEAR(CE_URL_S->redirecting_url);
  1536.     FREE_AND_CLEAR(CE_URL_S->authenticate);
  1537.     FREE_AND_CLEAR(CE_URL_S->proxy_authenticate);
  1538.  
  1539.     /* Build the request command.  (It must be free'd!!!) 
  1540.      *
  1541.      * build_http_request will assemble a string containing
  1542.      * the main request line, HTTP/1.0 MIME headers and
  1543.      * the post data (if it exits)
  1544.      */
  1545.     command_size = net_build_http_request(CE_URL_S,
  1546.                                   CE_FORMAT_OUT,
  1547.                                   CD_SEND_HTTP1, 
  1548.                                   (CD_USE_SSL_PROXY ? NULL : CD_PROXY_SERVER),
  1549.                                   CD_POSTING,
  1550.                                   CE_WINDOW_ID,
  1551.                                   &command,
  1552.                                   &CD_SENT_AUTHORIZATION,
  1553.                                   &CD_SENT_PROXY_AUTH);
  1554.  
  1555.     TRACEMSG(("Sending HTTP Request:\n---------------------------------"));
  1556.  
  1557.     CE_STATUS = (int) NET_BlockingWrite(cd->connection->sock, command, command_size);
  1558.  
  1559. #if defined(JAVA)
  1560. #if defined(DEBUG)
  1561.     if(MKLib_trace_flag)
  1562.       {
  1563.         NET_NTrace("Tx: ", 4);
  1564.         NET_NTrace(command, command_size);
  1565.       }
  1566. #endif /* DEBUG */
  1567. #endif /* JAVA */
  1568.     XP_FREE (command);  /* freeing the request */
  1569.  
  1570.     if (CE_STATUS < 0) 
  1571.       {
  1572.         int err = PR_GetError();
  1573.  
  1574.         if(err == PR_WOULD_BLOCK_ERROR)
  1575.             return(1); /* continue */
  1576.  
  1577.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_TCP_WRITE_ERROR, err);
  1578.  
  1579.         CD_NEXT_STATE= HTTP_ERROR_DONE;
  1580.  
  1581.         return(MK_TCP_WRITE_ERROR);
  1582.       }
  1583.  
  1584.  
  1585.     /* make sure these are empty
  1586.      */
  1587.     FREE_AND_CLEAR(CD_LINE_BUFFER); /* reset */
  1588.     CD_LINE_BUFFER_SIZE=0;          /* reset */
  1589.  
  1590.     if(CD_POSTING
  1591.         && CE_URL_S->post_data)
  1592.       {
  1593.         NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  1594.         NET_SetConnectSelect(CE_WINDOW_ID, cd->connection->sock);
  1595. #ifdef XP_WIN
  1596.         cd->calling_netlib_all_the_time = TRUE;
  1597.         NET_SetCallNetlibAllTheTime(CE_WINDOW_ID, "mkhttp");
  1598. #endif /* XP_WIN */
  1599.         CE_CON_SOCK = cd->connection->sock;
  1600.         CD_NEXT_STATE = HTTP_SEND_POST_DATA;
  1601.         return(0);
  1602.       }
  1603.   
  1604.     CD_NEXT_STATE = HTTP_PARSE_FIRST_LINE;
  1605.  
  1606.     /* Don't pause for read any more because we need to do
  1607.      * at least a single read right away to detect if the
  1608.      * connection is bad.  Apparently windows will queue a
  1609.      * write and not return a failure, but in fact the
  1610.      * connection has already been closed by the server.
  1611.      * Windows select will not even detect the exception
  1612.       * so we end up deadlocked.  By doing one read we
  1613.      * can detect errors immediately
  1614.      *
  1615.         * CD_PAUSE_FOR_READ = TRUE;
  1616.      */
  1617.  
  1618.     {
  1619.         char * nonProxyHost = NET_ParseURL(CE_URL_S->address, GET_HOST_PART);
  1620.         if (nonProxyHost) {
  1621.             char* msg = PR_smprintf(XP_GetString(XP_PROGRESS_WAIT_REPLY),
  1622.                                     nonProxyHost);
  1623.             if (msg) {
  1624.                 NET_Progress(CE_WINDOW_ID, msg);
  1625.                 XP_FREE(msg);
  1626.             }
  1627.             XP_FREE(nonProxyHost);
  1628.         }
  1629.     }
  1630.  
  1631.     return STATUS(CE_STATUS);
  1632.  
  1633. } /* end of net_send_http_request */
  1634.  
  1635. PRIVATE int
  1636. net_http_send_post_data (ActiveEntry *ce)
  1637. {
  1638.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  1639.     /* Default to not add_crlf_to_line_endings for HTTP. */
  1640.     XP_Bool add_crlf = FALSE;
  1641.   
  1642.  
  1643.     /* make sure the line buffer is large enough
  1644.      * for us to use as a buffer
  1645.      */
  1646.     if(cd->line_buffer_size < 200)
  1647.       {
  1648.         FREEIF(cd->line_buffer);
  1649.         cd->line_buffer = (char*)XP_ALLOC(256);
  1650.         cd->line_buffer_size = 256;
  1651.       }
  1652.  
  1653.     /* If the add_crlf field is set in the URL struct, find the
  1654.        entry corresponding to the current file being posted. */
  1655.     if (CE_URL_S->files_to_post && CE_URL_S->add_crlf) {
  1656.       int n = 0;
  1657.       while (CE_URL_S->files_to_post[n]) {
  1658.         n++;
  1659.       }
  1660.       /* n should now point after the last entry in files_to_post,
  1661.          which is the current file being uploaded. */      
  1662.       add_crlf = CE_URL_S->add_crlf[n];
  1663.     }
  1664.  
  1665.     /* returns 0 on done and negative on error
  1666.      * positive if it needs to continue.
  1667.      */
  1668.     CE_STATUS = NET_WritePostData(CE_WINDOW_ID, CE_URL_S,
  1669.                                   cd->connection->sock,
  1670.                                   &cd->write_post_data_data,
  1671.                                   add_crlf);
  1672.  
  1673.     cd->pause_for_read = TRUE;
  1674.  
  1675.     if(CE_STATUS == 0)
  1676.       {
  1677.         /* normal done
  1678.          */
  1679.         TRACEMSG(("End of post data data"));
  1680.  
  1681.         /* make sure these are empty
  1682.           */
  1683.          FREE_AND_CLEAR(cd->line_buffer); /* reset */
  1684.         cd->line_buffer_size=0;          /* reset */
  1685.  
  1686.         NET_ClearConnectSelect(CE_WINDOW_ID, cd->connection->sock);
  1687.         NET_SetReadSelect(CE_WINDOW_ID, cd->connection->sock);
  1688.         CE_CON_SOCK = NULL;
  1689.  
  1690.         {
  1691.             char * nonProxyHost = NET_ParseURL(CE_URL_S->address, GET_HOST_PART);
  1692.             if (nonProxyHost) {
  1693.                 char* msg = PR_smprintf(XP_GetString(XP_PROGRESS_WAIT_REPLY),
  1694.                                         nonProxyHost);
  1695.                 if (msg) {
  1696.                     NET_Progress(CE_WINDOW_ID, msg);
  1697.                     XP_FREE(msg);
  1698.                 }
  1699.                 XP_FREE(nonProxyHost);
  1700.             }
  1701.         }
  1702.  
  1703.         cd->next_state = HTTP_PARSE_FIRST_LINE;
  1704.         return(0);
  1705.       }
  1706.     else if(cd->total_size_of_files_to_post && ce->status > 0)
  1707.       {
  1708.           cd->total_amt_written += ce->status;
  1709.  
  1710.           FE_GraphProgress(ce->window_id, 
  1711.                          ce->URL_s, 
  1712.                          cd->total_amt_written, 
  1713.                          ce->status, 
  1714.                          cd->total_size_of_files_to_post);
  1715.         FE_SetProgressBarPercent(ce->window_id, 
  1716.                 cd->total_amt_written*100/cd->total_size_of_files_to_post);
  1717.       }
  1718.  
  1719.  
  1720.  
  1721.     return(CE_STATUS);
  1722. }
  1723.  
  1724. /* parse_http_mime_headers
  1725.  *
  1726.  * parses the mime headers as they are received from the
  1727.  * HTTP server.
  1728.  *
  1729.  * Returns the TCP status code
  1730.  * 
  1731.  */
  1732.  
  1733. PRIVATE int 
  1734. net_parse_http_mime_headers (ActiveEntry *ce)
  1735. {
  1736.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  1737.     char *line;
  1738.     char *value;
  1739.  
  1740.     CE_STATUS = NET_BufferedReadLine(cd->connection->sock, &line, &CD_LINE_BUFFER, 
  1741.                                     &CD_LINE_BUFFER_SIZE, &CD_PAUSE_FOR_READ);
  1742.  
  1743.     if(CE_STATUS < 0)
  1744.       {
  1745.         NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
  1746.  
  1747.         /* return TCP error
  1748.          */
  1749.         return MK_TCP_READ_ERROR;
  1750.       }
  1751.  
  1752.     if(CE_STATUS == 0)
  1753.       {
  1754.         /* if this is set just return so  we can use
  1755.           * the cached copythat
  1756.           */
  1757.         if(CD_USE_COPY_FROM_CACHE)
  1758.           {
  1759.             /* clear the URL content fields so that
  1760.              * the 304 object doesn't effect the actual
  1761.              * cache file
  1762.              */
  1763.             if(!CE_URL_S->preset_content_type)
  1764.                 FREE_AND_CLEAR(CE_URL_S->content_type);
  1765.             CE_URL_S->content_length = 0;
  1766.             CE_URL_S->real_content_length = 0;
  1767.             CE_URL_S->last_modified = 0;
  1768.             FREE_AND_CLEAR(CE_URL_S->content_encoding);
  1769.             FREE_AND_CLEAR(CE_URL_S->content_name);
  1770.             CD_NEXT_STATE = HTTP_DONE;
  1771.             CD_PAUSE_FOR_READ = FALSE;
  1772.             return(MK_USE_COPY_FROM_CACHE);
  1773.           }
  1774.  
  1775.         /* no mo data */
  1776.         if(CD_USE_SSL_PROXY && !CD_SSL_PROXY_SETUP_DONE)
  1777.           {
  1778.             /* we have now successfully initiated a ssl proxy
  1779.              * connection to a remote ssl host
  1780.              *
  1781.              * now we need to give the file descriptor
  1782.              * to the ssl library and let it initiate
  1783.              * a secure connection
  1784.              * after that we need to send a normal
  1785.              * http request
  1786.              *
  1787.               * ADD STUFF HERE KIPP!!!!
  1788.              *
  1789.              * fd is cd->connection->sock
  1790.              */
  1791.             if(ce->URL_s->files_to_post)
  1792.                 CD_NEXT_STATE = HTTP_BEGIN_UPLOAD_FILE;
  1793.             else
  1794.                 CD_NEXT_STATE = HTTP_SEND_REQUEST;
  1795.             CD_SSL_PROXY_SETUP_DONE = TRUE;
  1796.           }
  1797.         else if(ce->URL_s->files_to_post)
  1798.           {
  1799.             if(ce->URL_s->files_to_post[0]
  1800.                 && ce->URL_s->server_status/100 == 2)
  1801.               {
  1802.                   if(ce->URL_s->can_reuse_connection)
  1803.                   {
  1804.                     CD_NEXT_STATE = HTTP_BEGIN_UPLOAD_FILE;
  1805.                   }
  1806.                 else
  1807.                   {
  1808.                     NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  1809.                     NET_TotalNumberOfOpenConnections--;
  1810.  
  1811.                     /* close the old connection
  1812.                      */
  1813.                     PR_Close(cd->connection->sock);
  1814.                     cd->connection->sock = NULL;
  1815.  
  1816.                       CD_NEXT_STATE = HTTP_START_CONNECT;
  1817.                   }
  1818.               }
  1819.             else
  1820.               {
  1821.                 CD_NEXT_STATE = HTTP_DONE;
  1822.               }
  1823.           }
  1824.         else
  1825.           {
  1826.             CD_NEXT_STATE = HTTP_SETUP_STREAM;
  1827.           }
  1828.         CD_PAUSE_FOR_READ = FALSE;
  1829.         return(0);
  1830.       }
  1831.  
  1832.     if(!line)
  1833.         return(0);  /* wait for next line */
  1834.  
  1835.     TRACEMSG(("parse_http_mime_headers: Parsing headers, got line: %s",line));
  1836.  
  1837.     if(CD_ACTING_AS_PROXY)
  1838.       {
  1839.         /* save all the headers so we can pass them to the client
  1840.          * when neccessary
  1841.          */
  1842.         StrAllocCat(CD_SERVER_HEADERS, line);
  1843.         StrAllocCat(CD_SERVER_HEADERS, "\r\n");  /* add the \n back on */
  1844.       }
  1845.  
  1846.     /* check for end of MIME headers */
  1847.     if(*line == '\0' || *line == '\r')
  1848.       {
  1849.         TRACEMSG(("Finished parsing MIME headers"));
  1850.  
  1851.         CD_PAUSE_FOR_READ = FALSE;
  1852.  
  1853. HG07606
  1854.         if(ce->URL_s->files_to_post
  1855.                 && ce->URL_s->server_status/100 == 2)
  1856.           {
  1857.             if(ce->URL_s->files_to_post[0])
  1858.               {
  1859.                   if(ce->URL_s->can_reuse_connection)
  1860.                   {
  1861.                     CD_NEXT_STATE = HTTP_BEGIN_UPLOAD_FILE;
  1862.                   }
  1863.                 else
  1864.                   {
  1865.                     NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  1866.                     NET_TotalNumberOfOpenConnections--;
  1867.                 
  1868.                       /* close the old connection
  1869.                      */
  1870.                     PR_Close(cd->connection->sock);
  1871.                     cd->connection->sock = NULL;
  1872.  
  1873.                       CD_NEXT_STATE = HTTP_START_CONNECT;
  1874.                   }
  1875.               }
  1876.             else
  1877.               {
  1878.                 CD_NEXT_STATE = HTTP_DONE;
  1879.               }
  1880.           }
  1881.         else
  1882.           {
  1883.             CD_NEXT_STATE = HTTP_SETUP_STREAM;
  1884.           }
  1885.  
  1886.         return(0);
  1887.       }
  1888.  
  1889.     value = XP_STRCHR(line, ':');
  1890.     if(value)
  1891.         value++;
  1892.     NET_ParseMimeHeader(CE_FORMAT_OUT, CE_WINDOW_ID, CE_URL_S, line, value, TRUE);
  1893.  
  1894.     return(1);
  1895. }
  1896.  
  1897. /* setup HTTP/1.1 specific protocol defaults */
  1898. PRIVATE void
  1899. net_setup_http11_defaults(ActiveEntry *ce)
  1900. {
  1901.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  1902.  
  1903.     ce->URL_s->can_reuse_connection = TRUE;
  1904.  
  1905.     return;
  1906. }
  1907.  
  1908. /* parses the first line of the http server's response
  1909.  * and determines if it is an http1 or http/.9 server
  1910.  *
  1911.  * returns the tcp status code
  1912.  */
  1913. PRIVATE int 
  1914. net_parse_first_http_line (ActiveEntry *ce)
  1915. {
  1916.     char *line_feed=0;
  1917.     char *ptr;
  1918.     int line_size;
  1919.     int num_fields;
  1920.     char server_version[36];
  1921.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  1922.     char small_buf[MAX_FIRST_LINE_SIZE+16];
  1923.     Bool do_redirect = TRUE;
  1924.     
  1925.     TRACEMSG(("Entered: net_parse_first_http_line"));
  1926.  
  1927.     CE_STATUS = PR_Read(cd->connection->sock, small_buf, MAX_FIRST_LINE_SIZE+10);
  1928.  
  1929.     if(CE_STATUS == 0)
  1930.       {
  1931.         /* the server dropped the connection? */
  1932.          CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_ZERO_LENGTH_FILE);
  1933.            CD_NEXT_STATE = HTTP_ERROR_DONE;
  1934.         CD_PAUSE_FOR_READ = FALSE;
  1935.         return(MK_ZERO_LENGTH_FILE);
  1936.       }
  1937.     else if(CE_STATUS < 0)
  1938.       { 
  1939.         int s_error = PR_GetError();
  1940.         if (s_error == PR_WOULD_BLOCK_ERROR)
  1941.           {
  1942.             CD_PAUSE_FOR_READ = TRUE;
  1943.             return(0);
  1944.           }
  1945.         else
  1946.           {
  1947.             CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, s_error);
  1948.  
  1949.             /* return TCP error
  1950.              */
  1951.             return MK_TCP_READ_ERROR;
  1952.           }
  1953.       }
  1954.  
  1955.     /* this is where kipp says that I can finally query
  1956.      * for the security data.  We can't do it after the
  1957.      * connect since the handshake isn't done yet...
  1958.      */
  1959.     /* clear existing data
  1960.      */
  1961.     FREEIF(CE_URL_S->key_cipher);
  1962.     FREEIF(CE_URL_S->key_issuer);
  1963.     FREEIF(CE_URL_S->key_subject);
  1964.     if ( CE_URL_S->certificate ) {
  1965.        CERT_DestroyCertificate(CE_URL_S->certificate);
  1966.     }
  1967.  
  1968.     SSL_SecurityStatus(cd->connection->sock,
  1969.                        &CE_URL_S->security_on,
  1970.                        &CE_URL_S->key_cipher,
  1971.                        &CE_URL_S->key_size,
  1972.                        &CE_URL_S->key_secret_size,
  1973.                        &CE_URL_S->key_issuer,
  1974.                        &CE_URL_S->key_subject);
  1975.     CE_URL_S->certificate = SSL_PeerCertificate(cd->connection->sock);
  1976.  
  1977. #ifdef MOZILLA_CLIENT
  1978.     if ( ce->URL_s->redirecting_cert &&
  1979.         ( ! (CD_USE_SSL_PROXY && !CD_SSL_PROXY_SETUP_DONE) ) ) {
  1980.         /* don't do the redirect check when talking to the proxy,
  1981.          * wait for it to come through here a second time, when
  1982.          * we are really using SSL to talk to the real server.
  1983.          */
  1984.  
  1985.         PRBool compare;
  1986.         
  1987.         compare = CERT_CompareCertsForRedirection(ce->URL_s->certificate,
  1988.                                                   ce->URL_s->redirecting_cert);
  1989.  
  1990.         /* now that we are done with the redirecting cert destroy it */
  1991.         CERT_DestroyCertificate(ce->URL_s->redirecting_cert);
  1992.         ce->URL_s->redirecting_cert = NULL;
  1993.         
  1994.         if ( compare != PR_TRUE ) {
  1995.             /* certs are different */
  1996.         
  1997.             do_redirect = (Bool)SECNAV_SecurityDialog(CE_WINDOW_ID, 
  1998.                                         SD_REDIRECTION_TO_SECURE_SITE);
  1999.             if ( !do_redirect ) {
  2000.                 /* stop connection here!! */
  2001.                 CE_URL_S->error_msg = 0; /* XXX - is this right? */
  2002.  
  2003.                 /* return TCP error
  2004.                  */
  2005.                 return MK_TCP_READ_ERROR;
  2006.             }
  2007.         }
  2008.     }
  2009. #endif /* MOZILLA_CLIENT */
  2010.     
  2011.     /* CE_STATUS greater than 0 
  2012.      */
  2013.     BlockAllocCat(CD_LINE_BUFFER, CD_LINE_BUFFER_SIZE, small_buf, CE_STATUS);
  2014.     CD_LINE_BUFFER_SIZE += CE_STATUS;
  2015.  
  2016.     for(ptr = CD_LINE_BUFFER, line_size=0; line_size < CD_LINE_BUFFER_SIZE; ptr++, line_size++)
  2017.         if(*ptr == LF)
  2018.             {
  2019.             line_feed = ptr;
  2020.             break;
  2021.             }
  2022.  
  2023.     /* assume HTTP/.9 until we know better 
  2024.      */
  2025.     cd->protocol_version = POINT_NINE;
  2026.  
  2027.     if(line_feed)
  2028.       {
  2029.         *server_version = 0;
  2030.  
  2031.         *line_feed = '\0';
  2032.     
  2033.         num_fields = sscanf(CD_LINE_BUFFER, "%20s %d", server_version, &CE_URL_S->server_status);
  2034.     
  2035.         TRACEMSG(("HTTP: Scanned %d fields from first_line: %s", num_fields, CD_LINE_BUFFER));
  2036.     
  2037.         /* Try and make sure this is an HTTP/1.0 reply
  2038.           */
  2039.         if (num_fields == 2 || !XP_STRNCMP("HTTP/", server_version, 5))
  2040.           {
  2041.             double ver = atof(server_version+5);
  2042.  
  2043.             if(ver > 1.0)
  2044.             {
  2045.                 /* HTTP1.1 */
  2046.                 cd->protocol_version = ONE_POINT_ONE;
  2047.  
  2048.                 net_setup_http11_defaults(ce);
  2049.  
  2050.                 XP_ASSERT(ver == 1.1);
  2051.             }
  2052.             else
  2053.             {
  2054.                 /* HTTP1 */
  2055.                 cd->protocol_version = ONE_POINT_O;
  2056.  
  2057.                 XP_ASSERT(ver == 1.0  || ver == 0.0); /* allow 0 bug */
  2058.             }
  2059.           }
  2060.  
  2061.         /* put the line back the way it should be 
  2062.          */
  2063.         *line_feed = LF;
  2064.       }
  2065.     else if(CD_LINE_BUFFER_SIZE < MAX_FIRST_LINE_SIZE)
  2066.       {
  2067.         return(0); /* not ready to process */
  2068.       }
  2069.  
  2070.     if(cd->connection->prev_cache && cd->protocol_version == POINT_NINE)
  2071.        {
  2072.         /* got a non HTTP/1.0 or above response from
  2073.          * server that must support HTTP/1.0 since it
  2074.          * supports keep-alive.  The connection
  2075.          * must be in a bad state now so
  2076.          * restart the whole thang by going to the ERROR state
  2077.          */
  2078.         CD_NEXT_STATE = HTTP_ERROR_DONE;
  2079.       }
  2080.  
  2081.     /* if we are getting a successful read here
  2082.       * then the connection is valid
  2083.       */
  2084.     cd->connection_is_valid = TRUE;
  2085.  
  2086.     if(cd->protocol_version == POINT_NINE)
  2087.       {  /* HTTP/0.9 */
  2088.         NET_cinfo * ctype;
  2089.  
  2090.         TRACEMSG(("Receiving HTTP/0.9"));
  2091.         
  2092.         CE_URL_S->content_length = 0;
  2093.         CE_URL_S->real_content_length = 0;
  2094.         FREE_AND_CLEAR(CE_URL_S->content_encoding);
  2095.         FREE_AND_CLEAR(CE_URL_S->content_name);
  2096.  
  2097.         if(!CE_URL_S->preset_content_type)
  2098.           {
  2099.             FREE_AND_CLEAR(CE_URL_S->content_type);
  2100.  
  2101.              /* fake the content_type since we can't get it */
  2102.              ctype = NET_cinfo_find_type(CE_URL_S->address);
  2103.  
  2104.              /* treat unknown types as HTML
  2105.                */
  2106.              if(ctype->is_default)
  2107.                  StrAllocCopy(CE_URL_S->content_type, TEXT_HTML);
  2108.              else
  2109.                   StrAllocCopy(CE_URL_S->content_type, ctype->type);
  2110.  
  2111.              /* fake the content_encoding since we can't get it */
  2112.              StrAllocCopy(CE_URL_S->content_encoding, 
  2113.                          (NET_cinfo_find_enc(CE_URL_S->address))->encoding);
  2114.           }
  2115.  
  2116.         CD_NEXT_STATE = HTTP_SETUP_STREAM;
  2117.  
  2118.       } 
  2119.     else 
  2120.       {
  2121.         /* Decode full HTTP/1.0 or 1.1 response */
  2122.     
  2123.         TRACEMSG(("Receiving HTTP1 reply, status: %d", CE_URL_S->server_status));
  2124.  
  2125.         if(CE_URL_S->server_status != 304
  2126.             && (!CD_USE_SSL_PROXY || CD_SSL_PROXY_SETUP_DONE))
  2127.            {
  2128.             /* if we don't have a 304, zero all
  2129.              * the content headers so that they
  2130.              * don't interfere with the
  2131.              * incoming object
  2132.              *
  2133.              * don't zero these in the case of a SSL proxy
  2134.              * since this isn't the real request this
  2135.              * is just the connection open request response
  2136.              */
  2137.             if(!CE_URL_S->preset_content_type)
  2138.                 FREE_AND_CLEAR(CE_URL_S->content_type);
  2139.             CE_URL_S->content_length = 0;
  2140.             CE_URL_S->real_content_length = 0;
  2141.             FREE_AND_CLEAR(CE_URL_S->content_encoding);
  2142.             FREE_AND_CLEAR(CE_URL_S->content_name);
  2143.           }
  2144.  
  2145.         switch (CE_URL_S->server_status / 100) 
  2146.           {
  2147.                 case 1:
  2148.                 if(CE_URL_S->server_status == 100)
  2149.                 {
  2150.                     char * end_of_line;
  2151.                     int cur_line_size;
  2152.  
  2153.                     /* 100 continue.  Ignore line and continue looking
  2154.                       * for first line
  2155.                       */
  2156.  
  2157.                     /* strip the "HTTP/1.1 100 Continue" from the line buffer */
  2158.                     end_of_line = line_feed;
  2159.                     cur_line_size = (end_of_line - cd->line_buffer)+1;
  2160.  
  2161.                     /* absorb any blank lines after the 100 continue */
  2162.                     while(cd->line_buffer_size > cur_line_size)
  2163.                     {
  2164.                         if(line_feed[1] == CR || line_feed[1] == LF)
  2165.                         {
  2166.                             cur_line_size++;
  2167.                             end_of_line++;
  2168.                         }
  2169.                         else
  2170.                         {
  2171.                             /* anything else stop */
  2172.                             break;
  2173.                         }
  2174.                     }
  2175.  
  2176.                     cd->line_buffer_size -= cur_line_size;
  2177.                     if(cd->line_buffer_size)
  2178.                         XP_MEMMOVE(cd->line_buffer, end_of_line+1, cd->line_buffer_size); 
  2179.  
  2180.                     /* by not setting CD_NEXT_STATE to something different
  2181.                      * we will come back to this function and look for another
  2182.                      * first line.
  2183.                      */
  2184.                     return(0);
  2185.                     
  2186.                 }
  2187.                 break;
  2188.  
  2189.               case 2:   /* Succesful reply */
  2190.  
  2191.                 /* Since we
  2192.                   * are getting a new copy, delete the old one
  2193.                   * from the cache
  2194.                   */
  2195. #ifdef MOZILLA_CLIENT
  2196.                 NET_RemoveURLFromCache(CE_URL_S);
  2197. #endif
  2198.  
  2199.                 if((CE_URL_S->server_status == 204 
  2200.                     || CE_URL_S->server_status == 201)
  2201.                    && !CD_ACTING_AS_PROXY) 
  2202.                   {
  2203.                     if(ce->URL_s->files_to_post && ce->URL_s->files_to_post[0])
  2204.                       {
  2205.                           /* fall through since we need to get
  2206.                          * the headers to complete the
  2207.                          * file transfer
  2208.                          */
  2209.                       }
  2210.                     else
  2211.                       {
  2212.                         CE_STATUS = MK_NO_ACTION;
  2213.                           CD_NEXT_STATE = HTTP_ERROR_DONE;
  2214.                         return STATUS(CE_STATUS);
  2215.                       }
  2216.                   }
  2217.                 else if(cd->partial_cache_file
  2218.                            && ce->URL_s->range_header
  2219.                            && CE_URL_S->server_status != 206)
  2220.                     {
  2221.                     /* we asked for a range and got back
  2222.                       * the whole document.  Something
  2223.                       * went wrong, error out.
  2224.                       */
  2225.                        CE_STATUS = MK_TCP_READ_ERROR;
  2226.                     ce->URL_s->error_msg = NET_ExplainErrorDetails(
  2227.                                                             MK_TCP_READ_ERROR, 
  2228.                                                             XP_ERRNO_EIO);
  2229.                     CD_NEXT_STATE = HTTP_ERROR_DONE;
  2230.                     return(CE_STATUS);
  2231.                     }
  2232.  
  2233.                 break;
  2234.                 
  2235.               case 3:   /* redirection and other such stuff */
  2236.  
  2237.                 if(!CD_ACTING_AS_PROXY 
  2238.                      && (CE_URL_S->server_status == 301 || CE_URL_S->server_status == 302))
  2239.                   {
  2240.                    /* Redirect with GET only (change POST to get)
  2241.                     *
  2242.                     * Supported within the HTTP module.  
  2243.                     * Will retry after mime parsing 
  2244.                     */
  2245.                     TRACEMSG(("Got Redirect code"));
  2246.                     CD_DOING_REDIRECT = TRUE;
  2247.                   }
  2248.                 if(!CD_ACTING_AS_PROXY && CE_URL_S->server_status == 307)
  2249.                   {
  2250.                    /* Redirect without changing METHOD
  2251.                     * 
  2252.                     * Supported within the HTTP module.  
  2253.                     * Will retry after mime parsing 
  2254.                     */
  2255.                     TRACEMSG(("Got Redirect code"));
  2256.                     CD_DOING_REDIRECT = TRUE;
  2257.                     cd->save_redirect_method = TRUE;
  2258.                   }
  2259.                 else if(CE_URL_S->server_status == 304)
  2260.                   {
  2261.                     /* use the copy from the cache since it wasn't modified 
  2262.                      *
  2263.                      *  note: this will work with proxy clients too
  2264.                      */
  2265.                     if(CE_URL_S->last_modified)
  2266.                       {
  2267. #ifdef MOZILLA_CLIENT
  2268.                         /* check to see if we just now entered a secure space
  2269.                          *
  2270.                          * don't do if this is coming from history
  2271.                          * don't do this if about to redirect
  2272.                          */
  2273.                         if(CE_URL_S->security_on
  2274.                             && (CE_FORMAT_OUT == FO_CACHE_AND_PRESENT 
  2275.                                 || CE_FORMAT_OUT == FO_PRESENT)
  2276.                             && !CE_URL_S->history_num)
  2277.                           {
  2278.                             History_entry * h = SHIST_GetCurrent(&CE_WINDOW_ID->hist);
  2279.                     
  2280.                             if(!h || !h->security_on)
  2281.                                 SECNAV_SecurityDialog(CE_WINDOW_ID, 
  2282.                                                       SD_ENTERING_SECURE_SPACE);
  2283.                           }
  2284. #endif /* MOZILLA_CLIENT */
  2285.  
  2286.                            CD_USE_COPY_FROM_CACHE = TRUE;
  2287.                         /* no longer return since we need to parse
  2288.                          * headers from the server
  2289.                          *
  2290.                          * return(MK_USE_COPY_FROM_CACHE);  
  2291.                          */
  2292.                       }
  2293.  
  2294.                     /* else continue since the server messed up
  2295.                      * and sent us a 304 even without us having sent
  2296.                      * it an if-modified-since header
  2297.                      */
  2298.                   }
  2299.                 break;
  2300.                 
  2301.               case 4:    /* client error */
  2302.  
  2303.                 CE_URL_S->preset_content_type = FALSE;
  2304.  
  2305.                 if(CE_URL_S->server_status == 401 && !CD_ACTING_AS_PROXY)
  2306.                   {
  2307.                     /* never do this if acting as a proxy 
  2308.                      * If we are a proxy then just pass on 
  2309.                      * the headers and the document.
  2310.                      *
  2311.                      * if authorization_required is set we will check
  2312.                      * below after parsing the MIME headers to see
  2313.                      * if we should redo the request with an authorization
  2314.                      * string 
  2315.                      */
  2316.                     CD_AUTH_REQUIRED = TRUE;
  2317.  
  2318.                     /* Since we
  2319.                      * are getting a new copy, delete the old one
  2320.                      * from the cache
  2321.                      */
  2322. #ifdef MOZILLA_CLIENT
  2323.                     NET_RemoveURLFromCache(CE_URL_S);
  2324. #endif
  2325.  
  2326.                     /* we probably want to cache this unless
  2327.                      * the user chooses not to authorize himself
  2328.                      */
  2329.                   }
  2330.                 else if (CE_URL_S->server_status == 407 && !CD_ACTING_AS_PROXY)
  2331.                   {
  2332.                     /* This happens only if acting as a client */
  2333.                     CD_PROXY_AUTH_REQUIRED = TRUE;
  2334.  
  2335.                     /* we probably want to cache this unless
  2336.                      * the user chooses not to authorize himself
  2337.                      */
  2338.                   }
  2339.                 else
  2340.                   {
  2341.                     /* don't cache unless we have a succesful reply
  2342.                      */
  2343.                     TRACEMSG(("Server did not return success: NOT CACHEING!!"));
  2344.                     CE_URL_S->dont_cache = TRUE;
  2345.  
  2346.                     /* all other codes should be displayed */
  2347.                   }
  2348.                 break;
  2349.     
  2350.               case 5:    /* server error code */
  2351.                 TRACEMSG(("Server did not return success: NOT CACHEING!!!"));
  2352.                 CE_URL_S->dont_cache = TRUE;
  2353.                 CE_URL_S->preset_content_type = FALSE;
  2354. #ifdef DO_503
  2355.                 if(CE_URL_S->server_status == 503 && !CD_ACTING_AS_PROXY)
  2356.                   {
  2357.                     CD_SERVER_BUSY_RETRY = TRUE;
  2358.                   }
  2359. #endif /* DO_503 */
  2360.                 
  2361.                 /* display the error results */
  2362.                 break;
  2363.                 
  2364.               default:  /* unexpected reply code */
  2365.                 {
  2366.                   char message_buffer[256];
  2367.                   XP_SPRINTF(message_buffer,
  2368.                              XP_GetString(XP_ALERT_UNKNOWN_STATUS),
  2369.                              CE_URL_S->server_status);
  2370.                   FE_Alert(CE_WINDOW_ID, message_buffer);
  2371.  
  2372.                   /* don't cache unless we have a succesful reply
  2373.                    */
  2374.                   TRACEMSG(("Server did not return 200: NOT CACHEING!!!"));
  2375.                   CE_URL_S->dont_cache = TRUE;
  2376.                 }
  2377.                 break;
  2378.             } /* Switch on server_status/100 */
  2379.  
  2380.         CD_NEXT_STATE = HTTP_PARSE_MIME_HEADERS;
  2381.  
  2382.       } /* Full HTTP reply */
  2383.  
  2384.     return(0); /* good */
  2385.     
  2386. }
  2387.  
  2388. /* if we were posting a file and received an error put the
  2389.  * current file we were posting back on the end of the list
  2390.  * so that our state is correctly reset
  2391.  */
  2392. PRIVATE void
  2393. net_revert_post_data(ActiveEntry * ce)
  2394. {
  2395.     if(ce->URL_s->files_to_post && ce->URL_s->post_data)
  2396.     {
  2397.         /* find the end of the files to post array */
  2398.         int index=0;
  2399.  
  2400.         for(; ce->URL_s->files_to_post[index]; index++)
  2401.             ; /* null body */
  2402.  
  2403.         /* this will not explode even if the malloc fails */
  2404.         ce->URL_s->files_to_post[index] = XP_STRDUP(ce->URL_s->post_data);                    
  2405.  
  2406.         ce->URL_s->files_to_post[index+1] = NULL;
  2407.  
  2408.         if(ce->URL_s->post_to)
  2409.         {
  2410.             ce->URL_s->post_to[index] = XP_STRDUP(ce->URL_s->address);
  2411.  
  2412.             ce->URL_s->post_to[index+1] = NULL;
  2413.         }
  2414.     }
  2415. }
  2416.     
  2417. /* sets up the stream and performs special actions like redirect and
  2418.  * retry on authorization
  2419.  *
  2420.  * returns the tcp status code
  2421.  */
  2422. PRIVATE int
  2423. net_setup_http_stream(ActiveEntry * ce)
  2424. {
  2425.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  2426.     XP_Bool need_to_do_again = FALSE;
  2427.     MWContext * stream_context;
  2428.  
  2429.     TRACEMSG(("NET_ProcessHTTP: setting up stream"));
  2430.  
  2431.     /* save this since it can be changed in lots
  2432.      * of places.  This will be used for graph progress
  2433.      * and to terminate the tranfer
  2434.      */
  2435.     if(!ce->URL_s->high_range)
  2436.         cd->original_content_length = CE_URL_S->content_length;
  2437.     else
  2438.         cd->original_content_length = ce->URL_s->high_range 
  2439.                                       - ce->URL_s->low_range 
  2440.                                       + 1;
  2441.  
  2442.     if ((ce->URL_s->method == URL_HEAD_METHOD) && 
  2443.         ( CD_AUTH_REQUIRED == FALSE))
  2444.     {
  2445.       /* We only wanted the head, so we should stop doing anything else. */
  2446.       CD_NEXT_STATE = HTTP_DONE;
  2447.       return 0;
  2448.     }
  2449.  
  2450.     /* if this is set just return so that we can use
  2451.      * the cached copy
  2452.      */
  2453.     if(CD_USE_COPY_FROM_CACHE)
  2454.       {
  2455.         /* if this is a partial cache file situation
  2456.          * then we will keep going and switch later
  2457.          * on in this file.
  2458.          *
  2459.           * If it's not a partial cache file then
  2460.          * leave the HTTP module and go to the
  2461.          * file module to display the file
  2462.          */
  2463.         if(!cd->partial_cache_file)
  2464.           {
  2465.             /* clear the URL content fields so that
  2466.              * the 304 object doesn't effect the actual
  2467.              * cache file
  2468.              */
  2469.             if(!CE_URL_S->preset_content_type)
  2470.                 FREE_AND_CLEAR(CE_URL_S->content_type);
  2471.             CE_URL_S->content_length = 0;
  2472.             CE_URL_S->real_content_length = 0;
  2473.             FREE_AND_CLEAR(CE_URL_S->content_encoding);
  2474.             FREE_AND_CLEAR(CE_URL_S->content_name);
  2475.             CD_NEXT_STATE = HTTP_DONE;
  2476.             CD_PAUSE_FOR_READ = FALSE;
  2477.             return(MK_USE_COPY_FROM_CACHE);  
  2478.           }
  2479.         else
  2480.           {
  2481.             /* set the correct content length so that
  2482.              * the cache gets it right
  2483.              */
  2484.             ce->URL_s->content_length = ce->URL_s->real_content_length;
  2485.           }
  2486.       }
  2487.          
  2488.     /* do we need to start the tranfer over with authorization? 
  2489.      */
  2490.     if(CD_AUTH_REQUIRED)
  2491.       {
  2492.         /* clear to prevent tight loop */
  2493.         int status;
  2494.         NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  2495.         status = NET_AskForAuthString(CE_WINDOW_ID, 
  2496.                                 CE_URL_S, 
  2497.                                 CE_URL_S->authenticate,
  2498.                                 CE_URL_S->protection_template,
  2499.                                 CD_SENT_AUTHORIZATION);
  2500.  
  2501.         if(status == NET_RETRY_WITH_AUTH)
  2502.             need_to_do_again = TRUE;
  2503.         else
  2504.             CE_URL_S->dont_cache = TRUE;
  2505.  
  2506.         NET_SetReadSelect(CE_WINDOW_ID, cd->connection->sock);
  2507.       }
  2508. #if  defined(XP_WIN) && defined(MOZILLA_CLIENT)
  2509.  
  2510. #define COMPUSERVE_HEADER_NAME "Remote-Passphrase"
  2511.  
  2512.     else if(CE_URL_S->authenticate && !strncasecomp(CE_URL_S->authenticate, 
  2513.                                                      COMPUSERVE_HEADER_NAME, 
  2514.                                                      sizeof(COMPUSERVE_HEADER_NAME) - 1))
  2515.       {
  2516.         /* compuserve auth requires us to send all authenticate
  2517.           * headers into their code to verify the authentication
  2518.           */
  2519.         int status = WFE_DoCompuserveAuthenticate(CE_WINDOW_ID, 
  2520.                                                   CE_URL_S, 
  2521.                                                   CE_URL_S->authenticate);
  2522.  
  2523.         if(status == NET_AUTH_FAILED_DONT_DISPLAY)
  2524.           {                                                 
  2525.               CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_COMPUSERVE_AUTH_FAILED);
  2526.  
  2527.             return(MK_COMPUSERVE_AUTH_FAILED);            
  2528.           }
  2529.       }
  2530. #endif /* XP_WIN and MOZILLA_CLIENT */
  2531.                   
  2532.     if(CD_PROXY_AUTH_REQUIRED)
  2533.       {
  2534.         /* This was hacked in because proxy auth can be required when the Auto-config url
  2535.          * itself requires authorization. We used to ask for proxy auth only when the proxy was 
  2536.          * input directly into the prefs. Now we check to see if there's a pacurl (if there
  2537.          * is, there can't be a proxy url simultaneously) use it, otherwise we're using a
  2538.          * proxy from the prefs.
  2539.          */
  2540.         const char *tempURL=NULL;
  2541.         char *proxyServer=NULL;
  2542.  
  2543.         /* Figure out which kind of proxy we're using: PAC or straight proxy. 
  2544.          * DON'T FREE tempURL!!!
  2545.          */
  2546.         if ( (tempURL = net_GetPACUrl()) && (*tempURL) )
  2547.             proxyServer = NET_ParseURL(tempURL, GET_HOST_PART | GET_PATH_PART | GET_USERNAME_PART | GET_PASSWORD_PART);
  2548.         else
  2549.             proxyServer = CD_PROXY_SERVER;
  2550.  
  2551.         if(NET_AskForProxyAuth(CE_WINDOW_ID,
  2552.                                proxyServer,
  2553.                                CE_URL_S->proxy_authenticate,
  2554.                                CD_SENT_PROXY_AUTH))
  2555.             need_to_do_again = TRUE;
  2556.         else
  2557.             CE_URL_S->dont_cache = TRUE;
  2558.         /* Only free the our temp proxy server if it's not pointing to CD_PROXY_SERVER. 
  2559.          * We don't want to be freeing someone elses memory, we were just temporarily 
  2560.          * pointing to it. 
  2561.          */
  2562.         if (tempURL)
  2563.             XP_FREEIF(proxyServer);
  2564.       }
  2565.  
  2566.     if (need_to_do_again)
  2567.       {
  2568.         NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  2569.         PR_Close(cd->connection->sock);
  2570.         NET_TotalNumberOfOpenConnections--;
  2571.         cd->connection->sock = NULL;
  2572.         CD_SEND_HTTP1 = TRUE;
  2573.         CD_AUTH_REQUIRED = FALSE;
  2574.         CD_PROXY_AUTH_REQUIRED = FALSE;
  2575.         CD_NEXT_STATE = HTTP_START_CONNECT;
  2576.         CE_URL_S->last_modified = 0;  /* clear this so we don't get 304 loopage */
  2577.  
  2578.         /* we don't know if the connection is valid anymore */
  2579.         cd->connection_is_valid = FALSE;
  2580.  
  2581.         /* clear the buffer 
  2582.          */ 
  2583.         FREE_AND_CLEAR(CD_LINE_BUFFER);
  2584.         CD_LINE_BUFFER_SIZE = 0;
  2585.  
  2586.         /* if necessary */
  2587.         FREE_AND_CLEAR(CD_SERVER_HEADERS);
  2588.  
  2589.         return(0); /* continue */
  2590.       }
  2591.     else if (CD_DOING_REDIRECT && CE_URL_S->redirecting_url &&
  2592.             /* try and prevent a circular loop. wont work for dual doc loop
  2593.              */
  2594.                 XP_STRCMP(CE_URL_S->redirecting_url, CE_URL_S->address))
  2595.       {
  2596.         Bool do_redirect=TRUE;
  2597.         char *curURLHost, *redirectURLHost;
  2598.         char *curPort, *redirectPort;
  2599.  
  2600. #ifdef MOZILLA_CLIENT
  2601.         /* update the global history since we wont have the same
  2602.          * url later
  2603.          */
  2604.         GH_UpdateGlobalHistory(CE_URL_S);
  2605. #endif /* MOZILLA_CLIENT */
  2606.  
  2607.         /* Inserted for security reasons. Ie. java applets being told to redirect to places they shouldn't be.*/
  2608.         if(CE_URL_S->dontAllowDiffHostRedirect) {
  2609.  
  2610.             if( !(curURLHost = NET_ParseURL(CE_URL_S->address, GET_HOST_PART)) )
  2611.                 return MK_INTERRUPTED;
  2612.             if( !(redirectURLHost = NET_ParseURL(CE_URL_S->redirecting_url, GET_HOST_PART)) ) {
  2613.                 XP_FREE(curURLHost);
  2614.                 return MK_INTERRUPTED;
  2615.             }
  2616.  
  2617.             if ( (curPort = XP_STRCHR(curURLHost, ':')) != NULL)
  2618.                 *curPort='\0';
  2619.             if ( (redirectPort = XP_STRCHR(redirectURLHost, ':')) != NULL)
  2620.                 *redirectPort='\0';
  2621.  
  2622.             if(strcasecomp(curURLHost, redirectURLHost)) {
  2623.                 XP_FREE(curURLHost);
  2624.                 XP_FREE(redirectURLHost);
  2625.                 FREE_AND_CLEAR(CE_URL_S->redirecting_url);
  2626.                 CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_REDIRECT_ATTEMPT_NOT_ALLOWED);
  2627.                 return MK_REDIRECT_ATTEMPT_NOT_ALLOWED;
  2628.             }
  2629.  
  2630.             XP_FREE(curURLHost);
  2631.             XP_FREE(redirectURLHost);        
  2632.             
  2633.         } /* End URL_s->dontAllowDiffHostRedirect */
  2634.  
  2635.         if(CE_FORMAT_OUT == FO_CACHE_AND_PRESENT) {
  2636.             if(NET_IsURLSecure(CE_URL_S->address)) { /* current URL is secure*/
  2637.                 if(NET_IsURLSecure(CE_URL_S->redirecting_url)) {
  2638.                     /* new URL is secure */
  2639.                     /* save the cert of the guy doing the redirect */
  2640.                     ce->URL_s->redirecting_cert =
  2641.                         CERT_DupCertificate(ce->URL_s->certificate);
  2642.                 } else { /* new URL is not secure */
  2643.                     /* ask the user to confirm */
  2644.                     do_redirect = (Bool)SECNAV_SecurityDialog(CE_WINDOW_ID, 
  2645.                                                     SD_REDIRECTION_TO_INSECURE_DOC);
  2646.                 }
  2647.             }
  2648.           }
  2649.  
  2650.         /* OK, now we've got the redirection URL stored
  2651.          * in redirecting_url.
  2652.          * Now change the URL in the URL structure and do the whole
  2653.          * thing again
  2654.          */
  2655.         StrAllocCopy(CE_URL_S->address, CE_URL_S->redirecting_url);
  2656.  
  2657.         /* if we were posting a file and received an error put the
  2658.           * current file we were posting back on the end of the list
  2659.           * so that our state is correctly reset
  2660.           */
  2661.         net_revert_post_data(ce);  
  2662.  
  2663.         if(!cd->save_redirect_method)
  2664.         {
  2665.             FREE_AND_CLEAR(CE_URL_S->post_data);
  2666.             FREE_AND_CLEAR(CE_URL_S->post_headers);
  2667.             CE_URL_S->post_data_size = 0;
  2668.             CE_URL_S->method = URL_GET_METHOD;
  2669.         }
  2670.  
  2671.         /* clear these */
  2672.         if(!CE_URL_S->preset_content_type)
  2673.             FREE_AND_CLEAR(CE_URL_S->content_type);
  2674.         FREE_AND_CLEAR(CE_URL_S->content_encoding);
  2675.         CE_URL_S->content_length = 0;       /* reset */
  2676.         CE_URL_S->real_content_length = 0;  /* reset */
  2677.         CE_URL_S->last_modified = 0;        /* reset */
  2678.  
  2679.         CD_POSTING = FALSE;
  2680.  
  2681.         CE_URL_S->address_modified = TRUE;
  2682.  
  2683.         if(do_redirect)
  2684.             return(MK_DO_REDIRECT); /*fall out of HTTP and load the redirecting url */
  2685.         else
  2686.             return(MK_INTERRUPTED);
  2687.       }
  2688.     else if(CD_SERVER_BUSY_RETRY)
  2689.       {
  2690.         /* the redirecting mechanism works well for the retry
  2691.          * since it is really the same thing except the url stays
  2692.          * the same
  2693.          */
  2694.         return(MK_DO_REDIRECT); /* fall out of HTTP and reload the url */
  2695.       }
  2696.  
  2697. #ifdef MOZILLA_CLIENT
  2698.     /* check to see if we just now entered a secure space
  2699.      *
  2700.      * don't do if this is coming from history
  2701.      * don't do this if about to redirect
  2702.      */
  2703.     if(CE_URL_S->security_on
  2704.         && (CE_FORMAT_OUT == FO_CACHE_AND_PRESENT || CE_FORMAT_OUT == FO_PRESENT)
  2705.         && !CE_URL_S->history_num)
  2706.       {
  2707.         History_entry * h = SHIST_GetCurrent(&CE_WINDOW_ID->hist);
  2708.         XP_Bool warn = FALSE;
  2709.         
  2710.         if (h == NULL) {
  2711.             /* Deal with frames.  If the window doesn't have history,
  2712.              * then it is a new window or a new frame cell.
  2713.              */
  2714.             if ( ce->window_id->grid_parent != NULL ) {
  2715.                 h = SHIST_GetCurrent(&ce->window_id->grid_parent->hist);
  2716.                 if ( !h->security_on ) {
  2717.                     /* parent frame is not secure */
  2718.                     warn = TRUE;
  2719.                 }
  2720.             } else {
  2721.                 /* no parent frame - this is a top level window */
  2722.                 warn = TRUE;
  2723.             }
  2724.         } else if ( !h->security_on ) {
  2725.             warn = TRUE;
  2726.         }
  2727.         if ( warn ) {
  2728.             SECNAV_SecurityDialog(CE_WINDOW_ID, SD_ENTERING_SECURE_SPACE);
  2729.         }
  2730.       }
  2731. #endif /* MOZILLA_CLIENT */
  2732.  
  2733.     /* set a default content type if one wasn't given 
  2734.      */
  2735.     if(!CE_URL_S->content_type
  2736.         || !*CE_URL_S->content_type)
  2737.         StrAllocCopy(CE_URL_S->content_type, TEXT_HTML);
  2738.  
  2739.     /* If a stream previously exists from a partial cache
  2740.      * situation, reuse it
  2741.      */
  2742.     if(!CD_STREAM)
  2743.       {
  2744.         /* clear to prevent tight loop */
  2745.         NET_ClearReadSelect(ce->window_id, cd->connection->sock);
  2746.  
  2747. #ifdef MOZILLA_CLIENT
  2748.         /* if the context can't handle HTML then we
  2749.          * need to generate an HTML dialog to handle
  2750.          * the message
  2751.          */
  2752.         if(ce->URL_s->files_to_post && EDT_IS_EDITOR(ce->window_id))
  2753.           {
  2754.             Chrome chrome_struct;
  2755.  
  2756.             XP_MEMSET(&chrome_struct, 0, sizeof(Chrome));
  2757.  
  2758.             
  2759.                chrome_struct.is_modal = TRUE;
  2760.                chrome_struct.allow_close = TRUE;
  2761.                chrome_struct.allow_resize = TRUE;
  2762.                chrome_struct.show_scrollbar = TRUE;
  2763.                chrome_struct.w_hint = 400;
  2764.                chrome_struct.h_hint = 300;
  2765. #ifdef XP_MAC
  2766.             /* on Mac, topmost windows are floating windows not dialogs */
  2767.             chrome_struct.topmost = FALSE;
  2768.             /* disable commands to change to minimal menu bar; */
  2769.             /* avoids confusion about which commands are present */
  2770.             chrome_struct.disable_commands = TRUE;
  2771. #else
  2772.                chrome_struct.topmost = TRUE;
  2773. #endif
  2774.        
  2775.  
  2776.             stream_context = FE_MakeNewWindow(ce->window_id, 
  2777.                                                   NULL, 
  2778.                                                   NULL, 
  2779.                                                   &chrome_struct);
  2780.             if(!stream_context)
  2781.                 return (MK_OUT_OF_MEMORY);
  2782.  
  2783.             /* zero out the post_data field so that it doesn't get
  2784.              * pushed onto the history stack.  Otherwise it can
  2785.              * get deleted when the history gets cleared
  2786.              */
  2787.             FREE_AND_CLEAR(ce->URL_s->post_data);
  2788.             ce->URL_s->post_data_is_file = FALSE;
  2789.           }
  2790.         else
  2791. #endif /* MOZILLA_CLIENT */
  2792.           {
  2793.             stream_context = CE_WINDOW_ID;
  2794.           }
  2795.  
  2796.         /* we can get here on server or proxy errors
  2797.          * if we proceed to build the stream with post_data
  2798.          * set then the file could get deleted by history
  2799.          * cleanup code.  Make sure we zero the field
  2800.          */
  2801.         if(ce->URL_s->files_to_post && ce->URL_s->post_data)
  2802.           {
  2803.             /* we shoved the file to post into the post data.
  2804.              * remove it so the history doesn't get confused
  2805.              * and try and delete the file.
  2806.              */
  2807.             FREE_AND_CLEAR(ce->URL_s->post_data);
  2808.             ce->URL_s->post_data_is_file = FALSE;
  2809.           }
  2810.  
  2811.         /* Set up the stream stack to handle the body of the message */
  2812.         CD_STREAM = NET_StreamBuilder(CE_FORMAT_OUT, 
  2813.                                       CE_URL_S, 
  2814.                                       stream_context);
  2815.  
  2816.         if (!CD_STREAM)
  2817.             {
  2818.             CE_STATUS = MK_UNABLE_TO_CONVERT;
  2819.             CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_CONVERT);
  2820.             return STATUS(CE_STATUS);
  2821.             }
  2822. HG94794
  2823.         NET_SetReadSelect(CE_WINDOW_ID, cd->connection->sock);
  2824.  
  2825.         if(ce->URL_s->files_to_post)
  2826.           {
  2827.               char * tmp_string = XP_STRDUP("<h2>Error uploading files</h2><b>The server responded:<b><hr><p>\n");
  2828.  
  2829.             if(tmp_string)
  2830.                 PUTSTRING(tmp_string);
  2831.           } 
  2832.       }
  2833.     else
  2834.       {
  2835.         /* check to see if it's a multipart respose.
  2836.          * if it is then we need to do some magic to
  2837.          * strip the multipart
  2838.          */
  2839.         if(!strncasecomp(ce->URL_s->content_type, "multipart", 9))
  2840.         {
  2841.             /* reset the state to parse_mime_headers to strip
  2842.              * the multipart headers off
  2843.              */
  2844.             CD_NEXT_STATE = HTTP_PARSE_MIME_HEADERS;
  2845.             return STATUS(CE_STATUS);
  2846.         }
  2847.       }
  2848.  
  2849.     if(CD_USE_COPY_FROM_CACHE)
  2850.       {
  2851.         /* we can only get here if it's a partial cache file */
  2852.         CD_NEXT_STATE = HTTP_BEGIN_PUSH_PARTIAL_CACHE_FILE;
  2853.         CD_USE_COPY_FROM_CACHE = FALSE;
  2854.       }
  2855.     else
  2856.       {
  2857.         /* start the graph progress indicator
  2858.           */
  2859.         FE_GraphProgressInit(CE_WINDOW_ID, 
  2860.                              CE_URL_S, 
  2861.                              cd->original_content_length);
  2862.         CD_DESTROY_GRAPH_PROGRESS = TRUE;  /* we will need to destroy it */
  2863.  
  2864.            CD_NEXT_STATE = HTTP_PULL_DATA;
  2865.  
  2866.         if(CD_ACTING_AS_PROXY && CD_SERVER_HEADERS)
  2867.             {
  2868.             CE_STATUS = PUTBLOCK(CD_SERVER_HEADERS, 
  2869.                                  XP_STRLEN(CD_SERVER_HEADERS));
  2870.             CD_DISPLAYED_SOME_DATA = TRUE;
  2871.             }
  2872.  
  2873.         {
  2874.             char * nonProxyHost = NET_ParseURL(CE_URL_S->address, GET_HOST_PART);
  2875.             if (nonProxyHost) {
  2876.                 char* msg = PR_smprintf(XP_GetString(XP_PROGRESS_TRANSFER_DATA),
  2877.                                         nonProxyHost);
  2878.                 if (msg) {
  2879.                     NET_Progress(CE_WINDOW_ID, msg);
  2880.                     XP_FREE(msg);
  2881.                 }
  2882.                 XP_FREE(nonProxyHost);
  2883.             }
  2884.         }
  2885.  
  2886.         /* Push though buffered data */
  2887.         if(CD_LINE_BUFFER_SIZE)
  2888.             {
  2889.             /* @@@ bug, check return status and only send
  2890.              * up to the return value
  2891.              */
  2892.             (*CD_STREAM->is_write_ready)(CD_STREAM);
  2893.             CE_STATUS = PUTBLOCK(CD_LINE_BUFFER, CD_LINE_BUFFER_SIZE);
  2894.             CE_BYTES_RECEIVED = CD_LINE_BUFFER_SIZE;
  2895.             FE_GraphProgress(CE_WINDOW_ID, 
  2896.                              CE_URL_S, 
  2897.                              CE_BYTES_RECEIVED, 
  2898.                              CD_LINE_BUFFER_SIZE, 
  2899.                              CD_ORIGINAL_CONTENT_LENGTH);
  2900.             CD_DISPLAYED_SOME_DATA = TRUE;
  2901.             }
  2902.       }
  2903.  
  2904.     FREE_AND_CLEAR(CD_LINE_BUFFER);
  2905.     CD_LINE_BUFFER_SIZE=0;
  2906.  
  2907.     /* check to see if we have read the whole object,
  2908.      * and finish the transfer if so.
  2909.      */
  2910.     if(CE_STATUS > -1
  2911.        && CD_ORIGINAL_CONTENT_LENGTH
  2912.        && CE_BYTES_RECEIVED >= CD_ORIGINAL_CONTENT_LENGTH)
  2913.       {
  2914.         /* normal end of transfer */
  2915.         CE_STATUS = MK_DATA_LOADED;
  2916.         CD_NEXT_STATE = HTTP_DONE;
  2917.         CD_PAUSE_FOR_READ = FALSE;
  2918.       }
  2919.  
  2920.     return STATUS(CE_STATUS);
  2921. }
  2922.  
  2923. /* begin pushing a partial cache file down the stream
  2924.  */
  2925. PRIVATE int
  2926. net_http_push_partial_cache_file(ActiveEntry *ce)
  2927. {
  2928.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  2929.     int32 write_ready, status;
  2930.     
  2931.     write_ready = (*cd->stream->is_write_ready)(cd->stream);
  2932.  
  2933.     write_ready = MIN(write_ready, NET_Socket_Buffer_Size);
  2934.  
  2935.     status = XP_FileRead(NET_Socket_Buffer, write_ready, cd->partial_cache_fp);
  2936.  
  2937.     if(status < 0)
  2938.       {
  2939.         /* @@@ This is the wrong error code
  2940.          */
  2941.         ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, 
  2942.                                                        SOCKET_ERRNO);
  2943.         return(MK_TCP_READ_ERROR);
  2944.       }
  2945.     else if(status == 0)    
  2946.       {
  2947.         /* all done with reading this file
  2948.          */
  2949.         NET_ClearFileReadSelect(ce->window_id, XP_Fileno(cd->partial_cache_fp));
  2950.         XP_FileClose(cd->partial_cache_fp);
  2951.         cd->partial_cache_fp = NULL;
  2952.  
  2953.         /* set these back in preperation for
  2954.          * using the http connection again
  2955.           */
  2956.         ce->socket = cd->connection->sock;
  2957.         ce->local_file = FALSE;
  2958.  
  2959.         /* add a request-range header
  2960.          */
  2961.         XP_ASSERT(!ce->URL_s->range_header);
  2962.         ce->URL_s->range_header = PR_smprintf("bytes=%ld-", 
  2963.                                               cd->partial_needed);
  2964.  
  2965.         /* the byterange part has not been gotten yet */
  2966.         ce->URL_s->last_modified = 0;
  2967.  
  2968.         /* we don't know if the connection is valid anymore 
  2969.          * because we are going to try it again
  2970.          */
  2971.         cd->connection_is_valid = FALSE;
  2972.  
  2973.         if(ce->URL_s->can_reuse_connection)
  2974.           {
  2975.             NET_SetReadSelect(ce->window_id, cd->connection->sock);
  2976.             cd->next_state = HTTP_SEND_REQUEST;
  2977.  
  2978.             /* set the connection to be from the connection cache
  2979.               * since we have used it once
  2980.               */
  2981.             cd->connection->prev_cache = TRUE;
  2982.           }
  2983.         else
  2984.           {
  2985.             NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  2986.             NET_ClearConnectSelect(CE_WINDOW_ID, cd->connection->sock);
  2987.             PR_Close(cd->connection->sock);
  2988.             NET_TotalNumberOfOpenConnections--;
  2989.             cd->connection->sock = NULL;
  2990.             cd->next_state = HTTP_START_CONNECT;
  2991.           }
  2992.  
  2993.         cd->reuse_stream = TRUE;
  2994.  
  2995.         return(0);
  2996.       }
  2997.  
  2998.     /* else, push the data read up the stream 
  2999.      */    
  3000.     status = (*cd->stream->put_block)(cd->stream, 
  3001.                                       NET_Socket_Buffer, 
  3002.                                       status);
  3003.  
  3004.     cd->pause_for_read = TRUE;
  3005.  
  3006.     return(status);
  3007. }
  3008.  
  3009. /* begin pushing a partial cache file down the stream
  3010.  */
  3011. PRIVATE int
  3012. net_http_begin_push_partial_cache_file(ActiveEntry *ce)
  3013. {
  3014.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  3015.     char *cache_file = ce->URL_s->cache_file;
  3016.     XP_File fp;
  3017.  
  3018.     if(!cache_file 
  3019.        || NULL == (fp = XP_FileOpen(cache_file, xpCache, XP_FILE_READ_BIN)))
  3020.       {
  3021.         ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_OPEN_FILE, 
  3022.                                                        cache_file);
  3023.         return(MK_UNABLE_TO_OPEN_FILE);
  3024.       }
  3025.  
  3026.     /* set up read select on the file instead of the socket
  3027.      */
  3028.     NET_ClearReadSelect(ce->window_id, cd->connection->sock);
  3029.     NET_SetFileReadSelect(ce->window_id, XP_Fileno(fp));
  3030.     ce->socket = NULL;
  3031.     ce->local_file = TRUE;
  3032.  
  3033.     cd->next_state = HTTP_PUSH_PARTIAL_CACHE_FILE;
  3034.  
  3035.     cd->partial_cache_fp = fp;
  3036.         
  3037.     return(net_http_push_partial_cache_file(ce));
  3038. }
  3039.  
  3040. /* pulls down all the data
  3041.  *
  3042.  * returns the tcp status code
  3043.  */
  3044. PRIVATE int
  3045. net_pull_http_data(ActiveEntry * ce)
  3046. {
  3047.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  3048.     unsigned int write_ready, read_size;
  3049.  
  3050.     TRACEMSG(("NET_ProcessHTTP: pulling data"));
  3051.  
  3052.     /* check to see if the stream is ready for writing
  3053.      */
  3054.     write_ready = (*CD_STREAM->is_write_ready)(CD_STREAM);
  3055.  
  3056.     if(!write_ready)
  3057.       {
  3058.         CD_PAUSE_FOR_READ = TRUE;
  3059.         return(0);  /* wait until we are ready to write */
  3060.       }
  3061.     else if(write_ready < (unsigned int) NET_Socket_Buffer_Size)
  3062.       {
  3063.         read_size = write_ready;
  3064.       }
  3065.     else
  3066.       {
  3067.         read_size = NET_Socket_Buffer_Size;
  3068.       }
  3069.  
  3070.     CE_STATUS = PR_Read(cd->connection->sock, NET_Socket_Buffer, read_size);
  3071.  
  3072.     CD_PAUSE_FOR_READ = TRUE;  /* pause for the next read */
  3073.  
  3074.     if(CE_STATUS > 0)
  3075.       {
  3076.         CE_BYTES_RECEIVED += CE_STATUS;
  3077.         FE_GraphProgress(CE_WINDOW_ID, 
  3078.                          CE_URL_S, 
  3079.                          CE_BYTES_RECEIVED, 
  3080.                          CE_STATUS, 
  3081.                          CD_ORIGINAL_CONTENT_LENGTH);
  3082.  
  3083.         CE_STATUS = PUTBLOCK(NET_Socket_Buffer, CE_STATUS); /* ALEKS */
  3084.         CD_DISPLAYED_SOME_DATA = TRUE;
  3085.  
  3086.         if(CD_ORIGINAL_CONTENT_LENGTH 
  3087.             && CE_BYTES_RECEIVED >= CD_ORIGINAL_CONTENT_LENGTH)
  3088.           {
  3089.             /* normal end of transfer */
  3090.             CE_STATUS = MK_DATA_LOADED;
  3091.              CD_NEXT_STATE = HTTP_DONE;
  3092.              CD_PAUSE_FOR_READ = FALSE;
  3093.           }
  3094.  
  3095.       }
  3096.     else if(CE_STATUS == 0)
  3097.       {
  3098.         /* transfer finished
  3099.          */
  3100.         TRACEMSG(("MKHTTP.c: Caught TCP EOF ending stream"));
  3101.  
  3102.         if(!CD_DISPLAYED_SOME_DATA)
  3103.           {
  3104.              CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_ZERO_LENGTH_FILE);
  3105.              CD_NEXT_STATE = HTTP_ERROR_DONE;
  3106.             CD_PAUSE_FOR_READ = FALSE;
  3107.             return(MK_ZERO_LENGTH_FILE);
  3108.            }
  3109.  
  3110.          /* return the server status instead of data loaded
  3111.           */
  3112.          CE_STATUS = MK_DATA_LOADED;
  3113.          CD_NEXT_STATE = HTTP_DONE;
  3114.          CD_PAUSE_FOR_READ = FALSE;
  3115.       }
  3116.     else /* error */
  3117.       {
  3118.         int err = PR_GetError();
  3119.  
  3120.         TRACEMSG(("TCP Error: %d", err));
  3121.  
  3122.         if (err == PR_WOULD_BLOCK_ERROR)
  3123.           {
  3124.             CD_PAUSE_FOR_READ = TRUE;
  3125.             return (0);
  3126.           }
  3127.  
  3128.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, err);
  3129.  
  3130.         /* return TCP error
  3131.          */
  3132.         return MK_TCP_READ_ERROR;
  3133.       }
  3134.  
  3135.      return STATUS(CE_STATUS);
  3136.  
  3137. }
  3138.  
  3139. /* begin loading an object from an http host
  3140.  *
  3141.  * proxy_server  If not empty, the name of a host and/or port that will
  3142.  *               act as a proxy server for the request.  If proxy_server
  3143.  *               is NULL then no proxy server is used
  3144.  *
  3145.  */
  3146. PRIVATE int32
  3147. net_HTTPLoad (ActiveEntry * ce)
  3148. {
  3149.     /* get memory for Connection Data */
  3150.     HTTPConData * cd = XP_NEW(HTTPConData);
  3151.     XP_Bool url_is_secure = FALSE;
  3152.     char *use_host;
  3153.  
  3154.     ce->con_data = cd;
  3155.     if(!ce->con_data)
  3156.       {
  3157.         CE_STATUS = MK_OUT_OF_MEMORY;
  3158.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  3159.         return STATUS(CE_STATUS);
  3160.       }
  3161.  
  3162.     /* kill any returns in the URL */
  3163.     XP_STRTOK(ce->URL_s->address, "\r");
  3164.     XP_STRTOK(ce->URL_s->address, "\n");
  3165.  
  3166.     /* init */
  3167.     XP_MEMSET(cd, 0, sizeof(HTTPConData));
  3168.     CD_PROXY_SERVER     = ce->proxy_addr;
  3169.     CD_PROXY_CONF       = ce->proxy_conf;
  3170.     CD_SEND_HTTP1       = TRUE;
  3171.  
  3172.     /* set partial_cache_file if the whole file is not 
  3173.      * cached
  3174.      */
  3175.     if(ce->URL_s->content_length < ce->URL_s->real_content_length)
  3176.       {
  3177.         cd->partial_cache_file = TRUE;
  3178.         cd->partial_needed = ce->URL_s->content_length;
  3179.  
  3180. #ifdef MOZILLA_CLIENT
  3181.         /* if this isn't true then partial cacheing is screwed */
  3182.         XP_ASSERT(NET_IsPartialCacheFile(ce->URL_s));
  3183. #else
  3184.         XP_ASSERT(0);
  3185. #endif /* MOZILLA_CLIENT */
  3186.       }
  3187.   
  3188.     if(CD_PROXY_SERVER)
  3189.       {
  3190.         use_host = XP_STRDUP(CD_PROXY_SERVER);
  3191.       }
  3192.     else
  3193.       {
  3194.         use_host = NET_ParseURL(ce->URL_s->address, GET_HOST_PART);
  3195.         if(!strncasecomp(ce->URL_s->address, "https:", 6))
  3196.             url_is_secure = TRUE;
  3197.       }
  3198.  
  3199.     if(!use_host)
  3200.        {
  3201.         FREE(ce->con_data);
  3202.         CE_STATUS = MK_OUT_OF_MEMORY;
  3203.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  3204.         return STATUS(CE_STATUS);
  3205.       }
  3206.  
  3207.     /* if we are useing the files_to_post method
  3208.      * make sure that the directory specified in the
  3209.      * URL contains a slash at the end, otherwise
  3210.      * it wont work
  3211.      */
  3212.     if(ce->URL_s->files_to_post)
  3213.       {
  3214.         int32 end = XP_STRLEN(ce->URL_s->address)-1;
  3215.         XP_StatStruct stat_entry;
  3216.         int i;
  3217.  
  3218.         if(ce->URL_s->address[end] != '/')
  3219.             StrAllocCat(ce->URL_s->address, "/");
  3220.  
  3221.         /* run through the list of files and
  3222.          * gather the total size
  3223.          */
  3224.         for(i=0; ce->URL_s->files_to_post[i]; i++)
  3225.             if(-1 != XP_Stat(ce->URL_s->files_to_post[i], 
  3226.                              &stat_entry,
  3227.                              xpFileToPost))
  3228.                 cd->total_size_of_files_to_post += stat_entry.st_size;
  3229.  
  3230.         /* start the graph progress indicator
  3231.           */
  3232.         FE_GraphProgressInit(ce->window_id, 
  3233.                              ce->URL_s, 
  3234.                              cd->total_size_of_files_to_post);
  3235.                                                     
  3236.         CD_DESTROY_GRAPH_PROGRESS = TRUE;  /* we will need to destroy it */
  3237.                                                                            
  3238. #ifdef EDITOR
  3239.         /* Don't show the dialog if the data is being delivered to a plug-in */
  3240.         if ( (CLEAR_CACHE_BIT(ce->format_out) != FO_PLUGIN)
  3241.             && (CLEAR_CACHE_BIT(ce->format_out) != FO_LOCATION_INDEPENDENCE))
  3242.         {
  3243.             FE_SaveDialogCreate(ce->window_id, i, ED_SAVE_DLG_PUBLISH);
  3244.             cd->destroy_file_upload_progress_dialog = TRUE;
  3245.         }
  3246. #endif /* EDITOR */
  3247.       }
  3248.  
  3249.     /* check for established connection and use it if available
  3250.      */
  3251.     if(http_connection_list)
  3252.       {
  3253.         HTTPConnection * tmp_con;
  3254.         XP_List * list_entry = http_connection_list;
  3255.  
  3256.         /* If the url is secure and we are using a proxy server 
  3257.           * then never use a cached connection
  3258.           */
  3259.         if(!cd->use_ssl_proxy)
  3260.           {
  3261.  
  3262.             while((tmp_con = (HTTPConnection *)XP_ListNextObject(list_entry))
  3263.                   != NULL)
  3264.               {
  3265.                 /* if the hostnames match up exactly 
  3266.                  * and security matches up.
  3267.                  * and the connection
  3268.                  * is not busy at the moment then reuse this connection.
  3269.                  */
  3270.                 if(!XP_STRCMP(tmp_con->hostname, use_host)
  3271.                    && url_is_secure == tmp_con->secure
  3272.                    && !tmp_con->busy)
  3273.                   {
  3274.                     cd->connection = tmp_con;
  3275.                     cd->connection->sock = cd->connection->sock;
  3276.                     NET_SetReadSelect(CE_WINDOW_ID, cd->connection->sock);
  3277.                     CE_SOCK = cd->connection->sock;
  3278.                     cd->connection->prev_cache = TRUE;  /* this was from the cache */
  3279.                     TRACEMSG(("Found cached HTTP connection: %d", cd->connection->sock));
  3280.  
  3281.                     /* reorder the connection in the list to keep most recently
  3282.                      * used connections at the end
  3283.                      */
  3284.                     XP_ListRemoveObject(http_connection_list, tmp_con);
  3285.                     XP_ListAddObjectToEnd(http_connection_list, tmp_con);
  3286.  
  3287.                     break;
  3288.                   }
  3289.               }
  3290.           }
  3291.       }
  3292.     else
  3293.       {
  3294.         /* initialize the connection list
  3295.          */
  3296.         http_connection_list = XP_ListNew();
  3297.       }
  3298.  
  3299.     if(cd->connection)
  3300.       {
  3301.         if(CD_USE_SSL_PROXY)
  3302.             CD_NEXT_STATE = HTTP_SEND_SSL_PROXY_REQUEST;
  3303.         else if(ce->URL_s->files_to_post)
  3304.             CD_NEXT_STATE = HTTP_BEGIN_UPLOAD_FILE;
  3305.         else
  3306.             CD_NEXT_STATE = HTTP_SEND_REQUEST;
  3307.  
  3308.         /* set the connection busy
  3309.          */
  3310.         cd->connection->busy = TRUE;
  3311.         NET_TotalNumberOfOpenConnections++;
  3312.       }
  3313.     else
  3314.       {
  3315.         /* build a control connection structure so we
  3316.          * can store the data as we go along
  3317.          */
  3318.         cd->connection = XP_NEW(HTTPConnection);
  3319.         if(!cd->connection)
  3320.           {
  3321.             CE_STATUS = MK_OUT_OF_MEMORY;
  3322.             CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  3323.             FREE(use_host);
  3324.             FREE(ce->con_data);
  3325.             return(-1);
  3326.           }
  3327.         XP_MEMSET(cd->connection, 0, sizeof(HTTPConnection));
  3328.   
  3329.         StrAllocCopy(cd->connection->hostname, use_host);
  3330.   
  3331.         cd->connection->secure = url_is_secure;
  3332.   
  3333.         cd->connection->prev_cache = FALSE;  /* this wasn't from the cache */
  3334.   
  3335.         cd->connection->sock = NULL;
  3336.   
  3337.         /* add this structure to the connection list even
  3338.          * though it's not really valid yet.
  3339.          * we will fill it in as we go and if
  3340.          * an error occurs will will remove it from the
  3341.          * list.  No one else will be able to use it since
  3342.          * we will mark it busy.
  3343.          */
  3344.         XP_ListAddObject(http_connection_list, cd->connection);
  3345.  
  3346.         /* set the connection busy
  3347.          */
  3348.         cd->connection->busy = TRUE;
  3349.  
  3350.         /* if the connection list is larger than MAX_CACHED_HTTP_CONNECTIONS 
  3351.          * trim it down
  3352.          */
  3353.         if(XP_ListCount(http_connection_list) > MAX_CACHED_HTTP_CONNECTIONS)
  3354.           {
  3355.             HTTPConnection *tmp_con;
  3356.             XP_List * list_entry = http_connection_list;
  3357.  
  3358.             TRACEMSG(("More than %d cached connections.  Deleteing one...",
  3359.                       MAX_CACHED_HTTP_CONNECTIONS));
  3360.     
  3361.             while((tmp_con = (HTTPConnection *)XP_ListNextObject(list_entry)) != NULL)
  3362.                 {
  3363.                 if(!tmp_con->busy)
  3364.                   {
  3365.  
  3366.                      if(!strncasecomp(tmp_con->hostname, "rl.", 3)
  3367.                          && strcasestr(tmp_con->hostname+2, ".netscape.com"))
  3368.                       {
  3369.                         /* if there is max plus one we are done, else
  3370.                          * continue on and remove one 
  3371.                          */
  3372.                         if(XP_ListCount(http_connection_list) 
  3373.                                         == MAX_CACHED_HTTP_CONNECTIONS+1)
  3374.                           {
  3375.                             break; /* from while */
  3376.                           }
  3377.  
  3378.                       }
  3379.                     else
  3380.                       {
  3381.                         /* remove the object */
  3382.                         XP_ListRemoveObject(http_connection_list, tmp_con);
  3383.                         PR_Close(tmp_con->sock);
  3384.                         FREE(tmp_con->hostname);
  3385.                         FREE(tmp_con);
  3386.                         break; /* from while */
  3387.                       }
  3388.                   }
  3389.               }
  3390.           }
  3391.   
  3392.         CD_NEXT_STATE = HTTP_START_CONNECT;
  3393.  
  3394.       }
  3395.  
  3396.     FREE(use_host);
  3397.  
  3398.     return STATUS (net_ProcessHTTP(ce));
  3399. }
  3400.  
  3401.  
  3402. /* NET_process_HTTP  will control the state machine that
  3403.  * loads an HTTP document
  3404.  *
  3405.  * returns negative if the transfer is finished or error'd out
  3406.  *
  3407.  * returns zero or more if the transfer needs to be continued.
  3408.  */
  3409. PRIVATE int32
  3410. net_ProcessHTTP (ActiveEntry *ce)
  3411. {
  3412.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  3413.  
  3414.     TRACEMSG(("Entering NET_ProcessHTTP"));
  3415.  
  3416.     CD_PAUSE_FOR_READ = FALSE; /* already paused; reset */
  3417.  
  3418.     while(!CD_PAUSE_FOR_READ)
  3419.     {
  3420.  
  3421.         switch(CD_NEXT_STATE)
  3422.         {
  3423.         case HTTP_START_CONNECT:
  3424.             CE_STATUS = net_start_http_connect(ce);
  3425.             break;
  3426.         
  3427.         case HTTP_FINISH_CONNECT:
  3428.             CE_STATUS = net_finish_http_connect(ce);
  3429.             break;
  3430.         
  3431.         case HTTP_SEND_SSL_PROXY_REQUEST:
  3432.             /* send ssl proxy init stuff
  3433.              */
  3434.             CE_STATUS = net_send_ssl_proxy_request(ce);
  3435.             break;
  3436.  
  3437.         case HTTP_BEGIN_UPLOAD_FILE:
  3438.             /* form a put request */
  3439.             ce->status = net_begin_upload_file (ce);
  3440.             break;
  3441. HG51096
  3442.         case HTTP_SEND_REQUEST:
  3443.             /* send HTTP request */
  3444.             CE_STATUS = net_send_http_request(ce);
  3445.             break;
  3446.  
  3447.         case HTTP_SEND_POST_DATA:
  3448.             CE_STATUS = net_http_send_post_data(ce);
  3449.             break;
  3450.         
  3451.         case HTTP_PARSE_FIRST_LINE:
  3452.             CE_STATUS = net_parse_first_http_line(ce);
  3453.             break;
  3454.         
  3455.         case HTTP_PARSE_MIME_HEADERS:
  3456.             CE_STATUS = net_parse_http_mime_headers(ce);
  3457.             break;
  3458.         
  3459.         case HTTP_SETUP_STREAM:
  3460.             CE_STATUS = net_setup_http_stream(ce);
  3461.             break;
  3462.  
  3463.         case HTTP_BEGIN_PUSH_PARTIAL_CACHE_FILE:
  3464.             ce->status = net_http_begin_push_partial_cache_file(ce);
  3465.             break;
  3466.  
  3467.         case HTTP_PUSH_PARTIAL_CACHE_FILE:
  3468.             ce->status = net_http_push_partial_cache_file(ce);
  3469.             break;
  3470.         
  3471.         case HTTP_PULL_DATA:
  3472.             CE_STATUS = net_pull_http_data(ce);
  3473.             break;
  3474.         
  3475.         case HTTP_DONE:
  3476.             NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  3477.             NET_TotalNumberOfOpenConnections--;
  3478.  
  3479.             if(ce->URL_s->can_reuse_connection && !CD_USE_SSL_PROXY)
  3480.               {
  3481.                 cd->connection->busy = FALSE;
  3482.               }
  3483.             else
  3484.               {
  3485.                 PR_Close(cd->connection->sock);
  3486.  
  3487.                 /* remove the connection from the cache list
  3488.                   * and free the data
  3489.                   */
  3490.                 XP_ListRemoveObject(http_connection_list, cd->connection);
  3491.                 if(cd->connection)
  3492.                   {
  3493.                     FREEIF(cd->connection->hostname);
  3494.                     FREE(cd->connection);
  3495.                   }
  3496.               }
  3497.  
  3498. #ifdef MOZILLA_CLIENT
  3499.             /* make any meta tag changes take effect
  3500.               */
  3501.              NET_RefreshCacheFileExpiration(CE_URL_S);  
  3502. #endif /* MOZILLA_CLIENT */
  3503.  
  3504.             if(CD_STREAM)
  3505.               {
  3506.                 COMPLETE_STREAM;
  3507.                 FREE(CD_STREAM);
  3508.                 CD_STREAM = 0;
  3509.               }
  3510.             CD_NEXT_STATE = HTTP_FREE;
  3511.             break;
  3512.         
  3513.         case HTTP_ERROR_DONE:
  3514.             if(cd->connection->sock != NULL)
  3515.               {
  3516.                 NET_ClearDNSSelect(CE_WINDOW_ID, cd->connection->sock);
  3517.                 NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  3518.                 NET_ClearConnectSelect(CE_WINDOW_ID, cd->connection->sock);
  3519.                 PR_Close(cd->connection->sock);
  3520.                 NET_TotalNumberOfOpenConnections--;
  3521.                 cd->connection->sock = NULL;
  3522.               }
  3523.  
  3524.             if(cd->partial_cache_fp)
  3525.               {
  3526.                 NET_ClearFileReadSelect(ce->window_id, 
  3527.                                        XP_Fileno(cd->partial_cache_fp));
  3528.                 XP_FileClose(cd->partial_cache_fp);
  3529.                 cd->partial_cache_fp = 0;
  3530.               }
  3531.  
  3532.  
  3533.             if(cd->connection->prev_cache 
  3534.                 && !cd->connection_is_valid
  3535.                 && ce->status != MK_INTERRUPTED)
  3536.               {
  3537.                 if(CD_STREAM && !cd->reuse_stream)
  3538.                   {
  3539.                     ABORT_STREAM(CE_STATUS);
  3540.                     FREE(CD_STREAM);
  3541.                     CD_STREAM = 0;
  3542.                   }
  3543.             
  3544.                 /* the connection came from the cache and
  3545.                  * may have been stale.  Try it again
  3546.                  */
  3547.                 /* clear any error message */
  3548.                 if(ce->URL_s->error_msg)
  3549.                   {
  3550.                     FREE(ce->URL_s->error_msg);
  3551.                     ce->URL_s->error_msg = NULL;
  3552.                   }
  3553.                 cd->next_state = HTTP_START_CONNECT;
  3554.                 ce->status = 0;
  3555.  
  3556.                 /* we don't know if the connection is valid anymore 
  3557.                   * because we are going to try it again
  3558.                   */
  3559.                 cd->connection_is_valid = FALSE;
  3560.  
  3561.                 cd->connection->prev_cache = FALSE;
  3562.  
  3563.         /* if we were posting a file and received an error put the
  3564.          * current file we were posting back on the end of the list
  3565.          * so that our state is correctly reset
  3566.          */
  3567.         net_revert_post_data(ce);
  3568.  
  3569.               }
  3570.             else
  3571.               {
  3572.                 CD_NEXT_STATE = HTTP_FREE;
  3573.  
  3574.                 if(CD_STREAM)
  3575.                   {
  3576.                     ABORT_STREAM(CE_STATUS);
  3577.                     FREE(CD_STREAM);
  3578.                     CD_STREAM = 0;
  3579.                   }
  3580.  
  3581.                 /* remove the connection from the cache list
  3582.                  * and free the data
  3583.                  */
  3584.                 XP_ListRemoveObject(http_connection_list, cd->connection);
  3585.                 FREEIF(cd->connection->hostname);
  3586.                 FREE(cd->connection);
  3587.               }
  3588.  
  3589.             break;
  3590.         
  3591.         case HTTP_FREE:
  3592.  
  3593.             /* close the file upload progress.  If a stream was created
  3594.              * then some sort of HTTP error occured.  Send in an error
  3595.              * code
  3596.              */         
  3597. #ifdef EDITOR
  3598.             if(cd->destroy_file_upload_progress_dialog) {
  3599.                 /* Convert from netlib errors to editor errors. */
  3600.                 ED_FileError error = ED_ERROR_NONE;
  3601.                 if ( (ce->URL_s->server_status != 204 && ce->URL_s->server_status != 201 )
  3602.                     || ce->status < 0 )
  3603.                     error = ED_ERROR_PUBLISHING;
  3604.                 FE_SaveDialogDestroy(ce->window_id, error, ce->URL_s->post_data);
  3605.                 /* FE_SaveDialogDestroy(ce->window_id, ce->URL_s->server_status != 204 ? -1 : ce->status, ce->URL_s->post_data); */
  3606.             }
  3607. #endif /* EDITOR */
  3608.  
  3609.             if(ce->URL_s->files_to_post && ce->URL_s->post_data)
  3610.               {
  3611.                   /* we shoved the file to post into the post data.
  3612.                  * remove it so the history doesn't get confused
  3613.                  * and try and delete the file.
  3614.                  */
  3615.                 FREE_AND_CLEAR(ce->URL_s->post_data);
  3616.                 ce->URL_s->post_data_is_file = FALSE;
  3617.               }
  3618.  
  3619.             if(CD_DESTROY_GRAPH_PROGRESS)
  3620.                  FE_GraphProgressDestroy(CE_WINDOW_ID, 
  3621.                                         CE_URL_S, 
  3622.                                         CD_ORIGINAL_CONTENT_LENGTH,
  3623.                                         CE_BYTES_RECEIVED);
  3624.       
  3625.             FREEIF(CD_LINE_BUFFER);
  3626.             FREEIF(CD_STREAM); /* don't forget the stream */
  3627.             FREEIF(CD_SERVER_HEADERS);
  3628.             FREEIF(cd->orig_host);
  3629.             if(CD_TCP_CON_DATA)
  3630.                 NET_FreeTCPConData(CD_TCP_CON_DATA);
  3631.             FREEIF(cd);
  3632.             JSCF_Cleanup();
  3633.             return STATUS (-1); /* final end */
  3634.         
  3635.         default: /* should never happen !!! */
  3636.             TRACEMSG(("HTTP: BAD STATE!"));
  3637.             CD_NEXT_STATE = HTTP_ERROR_DONE;
  3638.             break;
  3639.         }
  3640.  
  3641.         /* check for errors during load and call error 
  3642.          * state if found
  3643.          */
  3644.         if(CE_STATUS < 0 
  3645.            && CE_STATUS != MK_USE_COPY_FROM_CACHE
  3646.            && CD_NEXT_STATE != HTTP_FREE)
  3647.         {
  3648.  
  3649.             if (CE_STATUS == MK_MULTIPART_MESSAGE_COMPLETED)
  3650.               {
  3651.                 /* We found the end of a multipart/mixed response
  3652.                  * from a CGI script in a http keep-alive response
  3653.                  * That signifies the end of a message.
  3654.                   */
  3655.                 TRACEMSG(("mkhttp.c: End of multipart keep-alive response"));
  3656.         
  3657.                  CE_STATUS = MK_DATA_LOADED;
  3658.                  CD_NEXT_STATE = HTTP_DONE;
  3659.  
  3660.               }
  3661.             else if (CE_STATUS == MK_HTTP_TYPE_CONFLICT
  3662.                 /* Don't retry if were HTTP/.9 */
  3663.                 && !CD_SEND_HTTP1
  3664.                 /* Don't retry if we're posting. */
  3665.                 && !CD_POSTING)
  3666.               {
  3667.                 /* Could be a HTTP 0/1 compability problem. */
  3668.                 TRACEMSG(("HTTP: Read error trying again with HTTP0 request."));
  3669.                 NET_Progress (CE_WINDOW_ID, XP_GetString(XP_PROGRESS_TRYAGAIN));
  3670.  
  3671.                 NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  3672.                 NET_ClearConnectSelect(CE_WINDOW_ID, cd->connection->sock);
  3673. #ifdef XP_WIN
  3674.                 if(cd->calling_netlib_all_the_time)
  3675.                 {
  3676.                     NET_ClearCallNetlibAllTheTime(CE_WINDOW_ID, "mkhttp");
  3677.                 }
  3678. #endif /* XP_WIN */
  3679.                 NET_ClearDNSSelect(CE_WINDOW_ID, cd->connection->sock);
  3680.                 PR_Close(cd->connection->sock);
  3681.                 NET_TotalNumberOfOpenConnections--;
  3682.                 cd->connection->sock = NULL;
  3683.  
  3684.                 if(CD_STREAM)
  3685.                     (*CD_STREAM->abort) (CD_STREAM, CE_STATUS);
  3686.                 CD_SEND_HTTP1 = FALSE;
  3687.                 /* go back and send an HTTP0 request */
  3688.                 CD_NEXT_STATE = HTTP_START_CONNECT;
  3689.               }
  3690.             else
  3691.               {
  3692.                 CD_NEXT_STATE = HTTP_ERROR_DONE;
  3693.               }
  3694.             /* don't exit! loop around again and do the free case */
  3695.             CD_PAUSE_FOR_READ = FALSE;
  3696.         }
  3697.     } /* while(!CD_PAUSE_FOR_READ) */
  3698.     
  3699.     return STATUS(CE_STATUS);
  3700. }
  3701.  
  3702.  
  3703. /* abort the connection in progress
  3704.  */
  3705. PRIVATE int32
  3706. net_InterruptHTTP(ActiveEntry * ce)
  3707. {
  3708.     HTTPConData * cd = (HTTPConData *)ce->con_data;
  3709.  
  3710.     /* if we are currently pulling data and the data is
  3711.      * Textual then truncate the file, leave notification and
  3712.      * end normally
  3713.      */
  3714.     if(CD_NEXT_STATE == HTTP_PULL_DATA 
  3715.         && CE_URL_S->content_type
  3716.          && !strcasecomp(CE_URL_S->content_type, TEXT_HTML))
  3717.       {
  3718.         char buffer[127];
  3719.  
  3720.         if(!strcasecomp(CE_URL_S->content_type, TEXT_HTML))
  3721.             PR_snprintf(buffer, sizeof(buffer),
  3722.                 XP_GetString(XP_HR_TRANSFER_INTERRUPTED));
  3723.         else
  3724.             PR_snprintf(buffer, sizeof(buffer),
  3725.                 XP_GetString(XP_TRANSFER_INTERRUPTED));
  3726.  
  3727.         PUTSTRING(buffer);
  3728.  
  3729.         /* steps from HTTP_DONE duplicated, with the addition of
  3730.          * NET_RefreshCacheFileExpiration 
  3731.           */
  3732.         NET_ClearReadSelect(CE_WINDOW_ID, cd->connection->sock);
  3733.         PR_Close(cd->connection->sock);
  3734.         NET_TotalNumberOfOpenConnections--;
  3735.         ABORT_STREAM(MK_INTERRUPTED);
  3736.         FREE(CD_STREAM);
  3737.         CD_STREAM = 0;
  3738.  
  3739.         CE_URL_S->last_modified = 0;
  3740. #ifdef MOZILLA_CLIENT
  3741.         /* to make the last_modified change take effect 
  3742.          */
  3743.         NET_RefreshCacheFileExpiration(CE_URL_S);  
  3744. #endif /* MOZILLA_CLIENT */
  3745.  
  3746.         CD_NEXT_STATE = HTTP_FREE;
  3747.  
  3748.         CE_STATUS = MK_DATA_LOADED;
  3749.       }
  3750.     else
  3751.       {
  3752.         CD_NEXT_STATE = HTTP_ERROR_DONE;
  3753.         CE_STATUS = MK_INTERRUPTED;
  3754.       }
  3755.  
  3756.     return STATUS (net_ProcessHTTP(ce));
  3757. }
  3758.  
  3759. /* Free any memory that might be used in caching etc.
  3760.  */
  3761. PRIVATE void
  3762. net_CleanupHTTP(void)
  3763. {
  3764.     /* nothing so far needs freeing */
  3765.     return;
  3766. }
  3767.  
  3768. MODULE_PRIVATE void
  3769. NET_InitHTTPProtocol(void)
  3770. {
  3771.     static NET_ProtoImpl http_proto_impl;
  3772.  
  3773.     http_proto_impl.init = net_HTTPLoad;
  3774.     http_proto_impl.process = net_ProcessHTTP;
  3775.     http_proto_impl.interrupt = net_InterruptHTTP;
  3776.     http_proto_impl.cleanup = net_CleanupHTTP;
  3777.  
  3778.     NET_RegisterProtocolImplementation(&http_proto_impl, HTTP_TYPE_URL);
  3779.     NET_RegisterProtocolImplementation(&http_proto_impl, SECURE_HTTP_TYPE_URL);
  3780. }
  3781.  
  3782. #ifdef PROFILE
  3783. #pragma profile off
  3784. #endif
  3785.