зеркало из https://github.com/mozilla/pjs.git
330 строки
8.7 KiB
C
330 строки
8.7 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/* Please leave outside of ifdef for windows precompiled headers */
|
|
#include "xp.h"
|
|
#include "plstr.h"
|
|
#include "prmem.h"
|
|
#include "netutils.h"
|
|
#include "mkselect.h"
|
|
#include "mktcp.h"
|
|
#include "mkgeturl.h"
|
|
|
|
#ifdef MOZILLA_CLIENT
|
|
|
|
#include "cvchunk.h" /* prototype */
|
|
|
|
extern int MK_OUT_OF_MEMORY;
|
|
|
|
typedef enum {
|
|
FIND_CHUNK_SIZE,
|
|
READ_CHUNK,
|
|
STRIP_CRLF,
|
|
PARSE_FOOTER
|
|
} States;
|
|
|
|
typedef struct _DataObject {
|
|
NET_StreamClass *next_stream;
|
|
char *in_buf;
|
|
uint32 in_buf_size;
|
|
uint32 chunk_size;
|
|
uint32 amount_of_chunk_parsed;
|
|
States cur_state;
|
|
FO_Present_Types format_out;
|
|
MWContext *context;
|
|
URL_Struct *URL_s;
|
|
} DataObject;
|
|
|
|
|
|
/* unchunk the message and return MK_MULTIPART_MESSAGE_COMPLETED
|
|
* when end detected
|
|
*/
|
|
PRIVATE int net_ChunkedWrite (NET_StreamClass *stream, char* s, int32 l)
|
|
{
|
|
DataObject *obj=stream->data_object;
|
|
BlockAllocCat(obj->in_buf, obj->in_buf_size, s, l);
|
|
if(!obj->in_buf)
|
|
return MK_OUT_OF_MEMORY;
|
|
obj->in_buf_size += l;
|
|
|
|
while(obj->in_buf_size > 0)
|
|
{
|
|
if(obj->cur_state == FIND_CHUNK_SIZE)
|
|
{
|
|
char *line_feed;
|
|
char *semicolon;
|
|
char *end;
|
|
|
|
/* we don't have a current chunk size
|
|
* look for a new chunk size
|
|
*
|
|
* make sure the line has a CRLF
|
|
*/
|
|
if((line_feed = PL_strnchr(obj->in_buf, LF, obj->in_buf_size)) == NULL)
|
|
{
|
|
return 1; /* need more data */
|
|
}
|
|
|
|
*line_feed = '\0';
|
|
|
|
semicolon = PL_strnchr(obj->in_buf, ';', line_feed-obj->in_buf);
|
|
|
|
if(semicolon)
|
|
*semicolon = '\0';
|
|
|
|
end = semicolon ? semicolon : line_feed;
|
|
|
|
/* read the first integer and ignore any thing
|
|
* else on the line. Extensions are allowed
|
|
*/
|
|
obj->chunk_size = strtol(obj->in_buf, &end, 16);
|
|
|
|
/* strip everything up to the line feed */
|
|
obj->in_buf_size -= (line_feed+1) - obj->in_buf;
|
|
if(obj->in_buf_size)
|
|
memmove(obj->in_buf,
|
|
line_feed+1,
|
|
obj->in_buf_size);
|
|
|
|
if(obj->chunk_size == 0)
|
|
{
|
|
/* the stream should be done now */
|
|
obj->cur_state = PARSE_FOOTER;
|
|
}
|
|
else
|
|
{
|
|
obj->cur_state = READ_CHUNK;
|
|
}
|
|
|
|
}
|
|
else if(obj->cur_state == READ_CHUNK)
|
|
{
|
|
uint32 data_size;
|
|
int32 status;
|
|
|
|
/* take as much data as we have and push it up the stream
|
|
*/
|
|
|
|
data_size = MIN(obj->in_buf_size, obj->chunk_size-obj->amount_of_chunk_parsed);
|
|
|
|
status = (obj->next_stream->put_block)(obj->next_stream,
|
|
obj->in_buf,
|
|
data_size);
|
|
if(status < 0)
|
|
return status;
|
|
|
|
/* remove the part that has been pushed */
|
|
obj->in_buf_size -= data_size;
|
|
if(obj->in_buf_size)
|
|
memmove(obj->in_buf,
|
|
obj->in_buf+data_size,
|
|
obj->in_buf_size);
|
|
|
|
obj->amount_of_chunk_parsed += data_size;
|
|
|
|
if(obj->amount_of_chunk_parsed >= obj->chunk_size)
|
|
{
|
|
PR_ASSERT(obj->amount_of_chunk_parsed == obj->chunk_size);
|
|
/* reinit */
|
|
obj->amount_of_chunk_parsed = 0;
|
|
obj->cur_state = STRIP_CRLF;
|
|
}
|
|
}
|
|
else if(obj->cur_state == STRIP_CRLF)
|
|
{
|
|
if(PL_strnchr(obj->in_buf, LF, obj->in_buf_size) == NULL)
|
|
{
|
|
return 1; /* No LF, need more data. */
|
|
}
|
|
|
|
if(obj->in_buf_size > 1 && obj->in_buf[0] == CR && obj->in_buf[1] == LF)
|
|
{
|
|
/* strip two bytes */
|
|
obj->in_buf_size -= 2;
|
|
if(obj->in_buf_size)
|
|
memmove(obj->in_buf,
|
|
obj->in_buf+2,
|
|
obj->in_buf_size);
|
|
obj->cur_state = FIND_CHUNK_SIZE;
|
|
}
|
|
else if(obj->in_buf[0] == LF)
|
|
{
|
|
/* strip one bytes */
|
|
obj->in_buf_size -= 1;
|
|
if(obj->in_buf_size)
|
|
memmove(obj->in_buf,
|
|
obj->in_buf+1,
|
|
obj->in_buf_size);
|
|
obj->cur_state = FIND_CHUNK_SIZE;
|
|
}
|
|
else
|
|
{
|
|
if(obj->in_buf_size >= 2)
|
|
{
|
|
int status;
|
|
|
|
/* a fatal parse error */
|
|
PR_ASSERT(0);
|
|
|
|
/* just spew the buf to the screen */
|
|
status = (obj->next_stream->put_block)(obj->next_stream,
|
|
obj->in_buf,
|
|
obj->in_buf_size);
|
|
if(status < 0)
|
|
return status;
|
|
|
|
/* remove the part that has been pushed */
|
|
obj->in_buf_size = 0;
|
|
}
|
|
}
|
|
}
|
|
else if(obj->cur_state == PARSE_FOOTER)
|
|
{
|
|
char *line_feed;
|
|
char *value;
|
|
|
|
/* parse until we see two CRLF's in a row */
|
|
if((line_feed = PL_strnchr(obj->in_buf, LF, obj->in_buf_size)) == NULL)
|
|
{
|
|
return 1; /* need more data */
|
|
}
|
|
|
|
*line_feed = '\0';
|
|
|
|
/* strip the CR */
|
|
if(line_feed != obj->in_buf && *(line_feed-1) == CR)
|
|
*(line_feed-1) = '\0';
|
|
|
|
if(*obj->in_buf == '\0')
|
|
{
|
|
/* end of parse stream */
|
|
return MK_MULTIPART_MESSAGE_COMPLETED;
|
|
}
|
|
|
|
/* names are separated from values with a colon
|
|
*/
|
|
value = PL_strchr(obj->in_buf, ':');
|
|
if(value)
|
|
value++;
|
|
|
|
/* otherwise parse the line as a mime header */
|
|
NET_ParseMimeHeader(obj->format_out,
|
|
obj->context,
|
|
obj->URL_s,
|
|
obj->in_buf,
|
|
value,
|
|
FALSE);
|
|
|
|
/* strip the line from the buffer */
|
|
obj->in_buf_size -= (line_feed+1) - obj->in_buf;
|
|
if(obj->in_buf_size)
|
|
memmove(obj->in_buf,
|
|
line_feed+1,
|
|
obj->in_buf_size);
|
|
}
|
|
}
|
|
|
|
PR_ASSERT(obj->in_buf_size == 0);
|
|
|
|
return(1);
|
|
}
|
|
|
|
/* is the stream ready for writeing?
|
|
*/
|
|
PRIVATE unsigned int net_ChunkedWriteReady (NET_StreamClass * stream)
|
|
{
|
|
DataObject *obj=stream->data_object;
|
|
return (*obj->next_stream->is_write_ready)(obj->next_stream);
|
|
}
|
|
|
|
|
|
PRIVATE void net_ChunkedComplete (NET_StreamClass *stream)
|
|
{
|
|
DataObject *obj=stream->data_object;
|
|
(*obj->next_stream->complete)(obj->next_stream);
|
|
|
|
PR_Free(obj);
|
|
return;
|
|
}
|
|
|
|
PRIVATE void net_ChunkedAbort (NET_StreamClass *stream, int status)
|
|
{
|
|
DataObject *obj=stream->data_object;
|
|
(*obj->next_stream->abort)(obj->next_stream, status);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
MODULE_PRIVATE NET_StreamClass *
|
|
NET_ChunkedDecoderStream (int format_out,
|
|
void *data_obj,
|
|
URL_Struct *URL_s,
|
|
MWContext *window_id)
|
|
{
|
|
DataObject* obj;
|
|
NET_StreamClass* stream;
|
|
|
|
TRACEMSG(("Setting up display stream. Have URL: %s\n", URL_s->address));
|
|
|
|
stream = PR_NEW(NET_StreamClass);
|
|
if(stream == NULL)
|
|
return(NULL);
|
|
|
|
obj = PR_NEWZAP(DataObject);
|
|
if (obj == NULL)
|
|
return(NULL);
|
|
|
|
stream->name = "Chunked decoder";
|
|
stream->complete = (MKStreamCompleteFunc) net_ChunkedComplete;
|
|
stream->abort = (MKStreamAbortFunc) net_ChunkedAbort;
|
|
stream->put_block = (MKStreamWriteFunc) net_ChunkedWrite;
|
|
stream->is_write_ready = (MKStreamWriteReadyFunc) net_ChunkedWriteReady;
|
|
stream->data_object = obj; /* document info object */
|
|
stream->window_id = window_id;
|
|
|
|
/* clear the "chunked" encoding */
|
|
if(URL_s->transfer_encoding)
|
|
{
|
|
PR_FREEIF(URL_s->transfer_encoding);
|
|
URL_s->transfer_encoding = NULL;
|
|
}
|
|
else
|
|
{
|
|
PR_FREEIF(URL_s->content_encoding);
|
|
URL_s->content_encoding = NULL;
|
|
}
|
|
obj->next_stream = NET_StreamBuilder(format_out, URL_s, window_id);
|
|
|
|
if(!obj->next_stream)
|
|
{
|
|
PR_Free(obj);
|
|
PR_Free(stream);
|
|
return NULL;
|
|
}
|
|
|
|
obj->context = window_id;
|
|
obj->format_out = format_out;
|
|
obj->URL_s = URL_s;
|
|
|
|
TRACEMSG(("Returning stream from NET_ChunkedConverter\n"));
|
|
|
|
return stream;
|
|
}
|
|
|
|
#endif /* MOZILLA_CLIENT */
|