home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / cvactive.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  13.2 KB  |  483 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. #include "mkutils.h"
  19. #include "cvactive.h"
  20. #include "mkgeturl.h"
  21. #include "mkstream.h"
  22. #include "glhist.h"
  23. #include "xp.h"
  24. #include "merrors.h"
  25.  
  26.  
  27. extern int MK_OUT_OF_MEMORY;
  28.  
  29.  
  30. typedef struct _DataObject {
  31.     int               state;
  32.     NET_StreamClass  *next_stream;
  33.     char             *prev_buffer;
  34.     int32             prev_buffer_len;
  35.     MWContext        *window_id;
  36.     int               format_out;
  37.     URL_Struct       *URL_s;
  38.     XP_Bool              signal_at_end_of_multipart;
  39. } DataObject;
  40.  
  41. #define NORMAL_S            1
  42. #define FOUND_BOUNDARY_S    2
  43.  
  44. #define MAX_MIME_LINE 200
  45.  
  46. /* parse a mime/multipart stream.  The boundary is already
  47.  * known and we start off in the content of the original
  48.  * message/822 body.
  49.  *
  50.  * buffer data up to the size of the passed in data length
  51.  * for efficiency of the upstream module.
  52.  */
  53. PRIVATE int net_MultipleDocumentWrite (NET_StreamClass *stream, CONST char* s, int32 l)
  54. {
  55.     int32 i=0;
  56.     int32 line_length=1;
  57.     int   rv=0;
  58.     char *cp;
  59.     char *line;
  60.     char *push_buffer=NULL;
  61.     int32 push_buffer_size=0;
  62.     XP_Bool all_done=FALSE;
  63.     DataObject *obj=stream->data_object;
  64.     BlockAllocCat(obj->prev_buffer, obj->prev_buffer_len, s, l);
  65.     obj->prev_buffer_len += l;    
  66.  
  67.     if(!obj->prev_buffer)
  68.         return(MK_OUT_OF_MEMORY);
  69.  
  70.     line = obj->prev_buffer;
  71.  
  72.     /* try and find a line
  73.      */
  74.     for(cp=obj->prev_buffer; i < obj->prev_buffer_len; cp++, i++, line_length++)
  75.       {
  76.         if(*cp == '\n')
  77.           {
  78.             
  79.             switch(obj->state)
  80.               {
  81.                 case NORMAL_S:
  82.                   {
  83.                     char *cp2 = line;
  84.                     int blength = XP_STRLEN(obj->URL_s->boundary);
  85.  
  86.                     /* look for boundary.  We can rest assured that these
  87.                        XP_STRNCMP() calls are safe, because we know that the
  88.                        valid portion of the string starting at cp2 has a
  89.                        newline in it (at *cp), and we know that boundary
  90.                        strings never have newlines in them.  */
  91.                     if((!XP_STRNCMP(cp2, "--",2) && 
  92.                         !XP_STRNCMP(cp2+2, 
  93.                                     obj->URL_s->boundary, 
  94.                                     blength))
  95.                           || (!XP_STRNCMP(cp2, 
  96.                                     obj->URL_s->boundary, 
  97.                                     blength)))
  98.                       {
  99.                         TRACEMSG(("Found boundary: %s", obj->URL_s->boundary));
  100.                         obj->state = FOUND_BOUNDARY_S;
  101.     
  102.                         if(obj->next_stream)
  103.                           {
  104.  
  105.                             if(push_buffer)
  106.                               {
  107.                                 /* strip the last newline before the
  108.                                  * boundary
  109.                                  */
  110.                                 push_buffer_size--;
  111.                                 /* if there is a CR as well as a LF
  112.                                  * strip that too
  113.                                  */
  114.                                 if(push_buffer_size > 0 && push_buffer[push_buffer_size-1] == CR)
  115.                                     push_buffer_size--;
  116.                                 rv = (*obj->next_stream->put_block)
  117.                                                         (obj->next_stream, 
  118.                                                         push_buffer, 
  119.                                                         push_buffer_size);
  120.                                 FREE(push_buffer);
  121.                                 push_buffer = NULL; 
  122.                                 push_buffer_size = 0;
  123.                               }
  124.  
  125.                             TRACEMSG(("Completeing an open stream"));
  126.                             /* if this stream is not the last one, set a flag
  127.                                before completion to let completion do special stuff */
  128.                             XP_ASSERT(cp2 + blength <= cp);
  129.                                 /* Because the above XP_STRCMP calls succeeded.
  130.                                    Because this is true, we know the first call
  131.                                    to XP_STRNCMP below is always safe, but we
  132.                                    need to check lengths before we can be sure
  133.                                    the other call is safe. */
  134.  
  135.                             if(   (cp2 + blength + 2 < cp && 
  136.                                     !XP_STRNCMP(cp2+2+blength, "--",2))
  137.                                || !XP_STRNCMP(cp2+blength, "--",2))
  138.                               {
  139.                                 /* very last boundary */
  140.                                 obj->next_stream->is_multipart = FALSE;
  141.  
  142.                                 /* set the all_done flag when
  143.                                  * we have found the final boundary
  144.                                  */
  145.                                 all_done = TRUE;
  146.                               }
  147.                             else
  148.                               {
  149.                                 obj->next_stream->is_multipart = TRUE;
  150.                               }
  151.                             
  152.                             /* complete the last stream
  153.                               */
  154.                             (*obj->next_stream->complete)
  155.                                                 (obj->next_stream);
  156.                             FREE(obj->next_stream);
  157.                             obj->next_stream = NULL;
  158.                           }
  159.                             
  160.                         /* move the line ptr up to new data */
  161.                         line = cp+1;
  162.                         line_length=1; /* reset */
  163.  
  164.                         if(all_done && obj->signal_at_end_of_multipart)
  165.                             return(MK_MULTIPART_MESSAGE_COMPLETED);
  166.                         break;
  167.                       }
  168.                     else 
  169.                       {
  170.                         TRACEMSG(("Pushing line (actually buffering)"));
  171.  
  172.                         /* didn't find the boundary
  173.                          */
  174.                         if(obj->next_stream)
  175.                           {
  176.  
  177.                             BlockAllocCat(push_buffer, push_buffer_size,
  178.                                           line, line_length);
  179.                             push_buffer_size += line_length;
  180.                             if(!push_buffer)
  181.                                 return(MK_OUT_OF_MEMORY);
  182.                           }
  183.  
  184.                         /* move the line ptr up to new data */
  185.                         line = cp+1;
  186.                         line_length=0; /* reset */
  187.                       }
  188.                     break;
  189.                   }
  190.  
  191.                 case FOUND_BOUNDARY_S:
  192.  
  193.                     XP_ASSERT(*cp == '\n'); /* from the 'if' above */
  194.  
  195.                     /* terminate at the newline.
  196.                      * now 'line' points to a valid NULL terminated C string
  197.                      */
  198.                     *cp = '\0';
  199.  
  200.                     TRACEMSG(("Parsing header: >%s<", line));
  201.     
  202.                     /* parse mime headers
  203.                      * stop when a blank line is encountered
  204.                      */
  205.                     if(*line == '\0' || *line == '\r')
  206.                       {
  207.                         int format_out;
  208.                         obj->state = NORMAL_S;
  209.     
  210.                         TRACEMSG(("Found end of headers"));
  211.                         if (obj->URL_s->content_type == NULL)
  212.                             StrAllocCopy(obj->URL_s->content_type, TEXT_PLAIN);
  213.  
  214.                         /* abort all existing streams.  We
  215.                          * have to do this to prevent the
  216.                          * image lib and other things from
  217.                          * continuing to load the page after
  218.                          * we left.
  219.                          *
  220.                          * don't abort other streams if it's
  221.                          * just a new inline image or if the
  222.                          * stream is not going to the screen
  223.                          */
  224.                         if(CLEAR_CACHE_BIT(obj->format_out) != FO_INTERNAL_IMAGE
  225.                             && (!strncasecomp(obj->URL_s->content_type, 
  226.                                              "text", 4)
  227.                                 ||
  228.                                 !strncasecomp(obj->URL_s->content_type, 
  229.                                                 "image", 4)) )
  230.                           {
  231.                             NET_SilentInterruptWindow(obj->window_id);
  232.                             format_out = obj->format_out;
  233.                           }
  234.                         else
  235.                           {
  236.                             /* don't cache image animations... */
  237.                             format_out = CLEAR_CACHE_BIT(obj->format_out);
  238.                           }
  239.             
  240.                         /* libimg and libplugin use the fe_data to store 
  241.                          * urls data, so clear it only if its not them */
  242.                         if( (CLEAR_CACHE_BIT(obj->format_out) != FO_INTERNAL_IMAGE) 
  243.                               && (CLEAR_CACHE_BIT(obj->format_out) != FO_PLUGIN)
  244.                               && (CLEAR_CACHE_BIT(obj->format_out) != FO_BYTERANGE)
  245.                               && strncasecomp(obj->URL_s->content_type, "image", 5))
  246.                           {
  247.                             obj->URL_s->fe_data = NULL;
  248.                           }
  249.  
  250.                         /* build a stream
  251.                          */
  252.                         obj->next_stream = NET_StreamBuilder(format_out, 
  253.                                                               obj->URL_s, 
  254.                                                              obj->window_id);
  255.     
  256.                         if(!obj->next_stream)
  257.                             return(MK_UNABLE_TO_CONVERT);
  258.                         
  259.                       }
  260.                     else if(!strncasecomp(line, "CONTENT-TYPE:", 13))
  261.                       {
  262.     
  263.                         XP_STRTOK(line+13, ";"); /* terminate at ; */
  264.  
  265.                         StrAllocCopy(obj->URL_s->content_type, 
  266.                                      XP_StripLine(line+13));
  267.     
  268.                         if(!obj->URL_s->content_type || !*obj->URL_s->content_type)
  269.                             StrAllocCopy(obj->URL_s->content_type, TEXT_PLAIN);
  270.  
  271.                         TRACEMSG(("found new content_type: %s", 
  272.                                    obj->URL_s->content_type));
  273.  
  274.                       }
  275.                     else
  276.                       {
  277.                         /* Pass all other headers to the MIME header parser 
  278.                           */
  279.                         char *value = XP_STRCHR(line, ':');
  280.                         if(value)
  281.                             value++;
  282.                         NET_ParseMimeHeader(NET_AllowForeignCookies,
  283.                                             obj->window_id, 
  284.                                             obj->URL_s, 
  285.                                             line, 
  286.                                             value, FALSE);
  287.                       }
  288.                     line = cp+1;
  289.                     line_length = 0;
  290.                     break;
  291.  
  292.                 default:
  293.                     assert(0);
  294.                     break;
  295.                 
  296.               }
  297.           } /* end if */
  298.       } /* end for */
  299.  
  300.     if(line_length > MAX_MIME_LINE * 2)
  301.       {
  302.         int32 new_size;
  303.  
  304.         TRACEMSG(("Line too long pushing it"));
  305.  
  306.         if(obj->next_stream)
  307.           {
  308.             if(push_buffer)
  309.               {
  310.                 rv = (*obj->next_stream->put_block)(obj->next_stream, 
  311.                                                 push_buffer, 
  312.                                                 push_buffer_size);
  313.                 rv = (*obj->next_stream->put_block)(obj->next_stream, 
  314.                                                     line, 
  315.                                                     MAX_MIME_LINE);
  316.                 FREE(push_buffer);
  317.                 push_buffer = 0;
  318.                 push_buffer_size = 0;
  319.               }
  320.             else
  321.               {
  322.                 rv = (*obj->next_stream->put_block)(obj->next_stream, 
  323.                                                     line, 
  324.                                                     MAX_MIME_LINE);
  325.               }
  326.  
  327.             if(rv < 0)
  328.                 return(rv);
  329.           }
  330.  
  331.         /* newsize equals the old size minus the difference
  332.          * between line and the start of the old buffer and
  333.          * the MAX_MIME_LENGTH that we just wrote out
  334.          */
  335.         new_size = obj->prev_buffer_len - 
  336.                      ((line - obj->prev_buffer) + MAX_MIME_LINE);
  337.  
  338.         XP_MEMMOVE(obj->prev_buffer, line+MAX_MIME_LINE, new_size);
  339.         obj->prev_buffer_len = new_size;
  340.     
  341.         return(0);
  342.       }
  343.  
  344.     if(line != obj->prev_buffer)
  345.       {
  346.         /* some part of the line has been digested, get rid of
  347.          * the part that has been used
  348.          */
  349.         obj->prev_buffer_len -= (line - obj->prev_buffer);
  350.         XP_MEMMOVE(obj->prev_buffer, line, obj->prev_buffer_len);
  351.       }
  352.  
  353.     /* if there is anything in the push buffer send it now
  354.      */
  355.     if(push_buffer)
  356.       {
  357.         if(obj->next_stream)
  358.           {
  359.             TRACEMSG(("Pushing buffered data"));
  360.             rv = (*obj->next_stream->put_block)(obj->next_stream, 
  361.                                                 push_buffer, 
  362.                                                 push_buffer_size);
  363.           }
  364.         FREE(push_buffer);
  365.         if (rv < 0)
  366.             return rv;
  367.       }
  368.     
  369.     return(0);
  370. }
  371.  
  372. /* is the stream ready for writeing?
  373.  */
  374. PRIVATE unsigned int net_MultipleDocumentWriteReady (NET_StreamClass * stream)
  375. {
  376.   DataObject *obj=stream->data_object;
  377.   if(obj->next_stream)
  378.     return((*obj->next_stream->is_write_ready)(obj->next_stream));
  379.   else
  380.     return(MAX_WRITE_READY);
  381. }
  382.  
  383.  
  384. PRIVATE void net_MultipleDocumentComplete (NET_StreamClass *stream)
  385. {
  386.     DataObject *obj=stream->data_object;    
  387.  
  388.     if(obj->next_stream)
  389.       {
  390.         (*obj->next_stream->complete)(obj->next_stream);
  391.         FREE(obj->next_stream);
  392.       }
  393.  
  394.     FREEIF(obj->prev_buffer);
  395.     FREE(obj);
  396.  
  397.     return;
  398. }
  399.  
  400. PRIVATE void net_MultipleDocumentAbort (NET_StreamClass *stream, int status)
  401. {
  402.     DataObject *obj=stream->data_object;    
  403.     if(obj->next_stream)
  404.       {
  405.         (*obj->next_stream->abort)(obj->next_stream, status);
  406.         FREE(obj->next_stream);
  407.       }
  408.  
  409.     FREEIF(obj->prev_buffer);
  410.     FREE(obj);
  411.  
  412.     return;
  413. }
  414.  
  415.  
  416. PUBLIC NET_StreamClass * 
  417. CV_MakeMultipleDocumentStream (int         format_out,
  418.                                void       *data_object,
  419.                                URL_Struct *URL_s,
  420.                                MWContext  *window_id)
  421. {
  422.     DataObject* obj;
  423.     NET_StreamClass* stream;
  424.     
  425.     TRACEMSG(("Setting up display stream. Have URL: %s\n", URL_s->address));
  426.  
  427.     GH_UpdateGlobalHistory(URL_s);
  428.  
  429.     URL_s->is_active = TRUE;  /* set to disable view source */
  430.  
  431.     stream = XP_NEW(NET_StreamClass);
  432.     if(stream == NULL) 
  433.         return(NULL);
  434.  
  435.     obj = XP_NEW(DataObject);
  436.     if (obj == NULL) 
  437.         return(NULL);
  438.  
  439.     XP_MEMSET(obj, 0, sizeof(DataObject));
  440.  
  441.     if(CVACTIVE_SIGNAL_AT_END_OF_MULTIPART == (int) data_object)
  442.         obj->signal_at_end_of_multipart = TRUE;
  443.     
  444.     stream->name           = "Multiple Document";
  445.     stream->complete       = (MKStreamCompleteFunc) net_MultipleDocumentComplete;
  446.     stream->abort          = (MKStreamAbortFunc) net_MultipleDocumentAbort;
  447.     stream->put_block      = (MKStreamWriteFunc) net_MultipleDocumentWrite;
  448.     stream->is_write_ready = (MKStreamWriteReadyFunc) net_MultipleDocumentWriteReady;
  449.     stream->data_object    = obj;  /* document info object */
  450.     stream->window_id      = window_id;
  451.  
  452.     /* don't cache these
  453.     format_out = CLEAR_CACHE_BIT(format_out);
  454.      */
  455.  
  456.     /* enable clicking since it doesnt go through the cache 
  457.      * code
  458.      */
  459.     FE_EnableClicking(window_id);
  460.  
  461.     obj->next_stream = NULL;
  462.     obj->window_id  = window_id;
  463.     obj->format_out = format_out;
  464.     obj->URL_s      = URL_s;
  465.     obj->state      = NORMAL_S;
  466.  
  467.     /* make sure that we have a real boundary.
  468.       * if not fill in '--' as a boundary
  469.      */
  470.     if(!URL_s->boundary)
  471.         StrAllocCopy(URL_s->boundary, "--");
  472.  
  473.     /* overwrite the current content type with TEXT/PLAIN since
  474.      * we want that as the default content-type for
  475.      * body parts
  476.      */
  477.     StrAllocCopy(URL_s->content_type, TEXT_PLAIN);
  478.  
  479.     TRACEMSG(("Returning stream from NET_MultipleDocumentConverter\n"));
  480.  
  481.     return stream;
  482. }
  483.