File Annotation
Not logged in
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** Copyright (c) 2009 D. Richard Hipp
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: ** This program is free software; you can redistribute it and/or
737e76a69f 2009-03-30       drh: ** modify it under the terms of the GNU General Public
737e76a69f 2009-03-30       drh: ** License version 2 as published by the Free Software Foundation.
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: ** This program is distributed in the hope that it will be useful,
737e76a69f 2009-03-30       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
737e76a69f 2009-03-30       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
737e76a69f 2009-03-30       drh: ** General Public License for more details.
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: ** You should have received a copy of the GNU General Public
737e76a69f 2009-03-30       drh: ** License along with this library; if not, write to the
737e76a69f 2009-03-30       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
737e76a69f 2009-03-30       drh: ** Boston, MA  02111-1307, USA.
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: ** Author contact information:
737e76a69f 2009-03-30       drh: **   drh@hwaci.com
737e76a69f 2009-03-30       drh: **   http://www.hwaci.com/drh/
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: *******************************************************************************
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: ** This module implements the transport layer for the client side HTTP
737e76a69f 2009-03-30       drh: ** connection.  The purpose of this layer is to provide a common interface
737e76a69f 2009-03-30       drh: ** for both HTTP and HTTPS and to provide a common "fetch one line"
737e76a69f 2009-03-30       drh: ** interface that is used for parsing the reply.
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: #include "config.h"
737e76a69f 2009-03-30       drh: #include "http_transport.h"
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** State information
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: static struct {
945ecd1a8b 2009-04-11       drh:   int isOpen;             /* True when the transport layer is open */
945ecd1a8b 2009-04-11       drh:   char *pBuf;             /* Buffer used to hold the reply */
945ecd1a8b 2009-04-11       drh:   int nAlloc;             /* Space allocated for transportBuf[] */
945ecd1a8b 2009-04-11       drh:   int nUsed ;             /* Space of transportBuf[] used */
945ecd1a8b 2009-04-11       drh:   int iCursor;            /* Next unread by in transportBuf[] */
79be9028eb 2009-08-12       drh:   int nSent;              /* Number of bytes sent */
79be9028eb 2009-08-12       drh:   int nRcvd;              /* Number of bytes received */
945ecd1a8b 2009-04-11       drh:   FILE *pFile;            /* File I/O for FILE: */
945ecd1a8b 2009-04-11       drh:   char *zOutFile;         /* Name of outbound file for FILE: */
945ecd1a8b 2009-04-11       drh:   char *zInFile;          /* Name of inbound file for FILE: */
737e76a69f 2009-03-30       drh: } transport = {
79be9028eb 2009-08-12       drh:   0, 0, 0, 0, 0, 0, 0
737e76a69f 2009-03-30       drh: };
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** Return the current transport error message.
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: const char *transport_errmsg(void){
737e76a69f 2009-03-30       drh:   return socket_errmsg();
79be9028eb 2009-08-12       drh: }
79be9028eb 2009-08-12       drh: 
79be9028eb 2009-08-12       drh: /*
79be9028eb 2009-08-12       drh: ** Retrieve send/receive counts from the transport layer.  If "resetFlag"
79be9028eb 2009-08-12       drh: ** is true, then reset the counts.
79be9028eb 2009-08-12       drh: */
79be9028eb 2009-08-12       drh: void transport_stats(int *pnSent, int *pnRcvd, int resetFlag){
79be9028eb 2009-08-12       drh:   if( pnSent ) *pnSent = transport.nSent;
79be9028eb 2009-08-12       drh:   if( pnRcvd ) *pnRcvd = transport.nRcvd;
79be9028eb 2009-08-12       drh:   if( resetFlag ){
79be9028eb 2009-08-12       drh:     transport.nSent = 0;
79be9028eb 2009-08-12       drh:     transport.nRcvd = 0;
79be9028eb 2009-08-12       drh:   }
737e76a69f 2009-03-30       drh: }
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** Open a connection to the server.  The server is defined by the following
737e76a69f 2009-03-30       drh: ** global variables:
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: **   g.urlName        Name of the server.  Ex: www.fossil-scm.org
737e76a69f 2009-03-30       drh: **   g.urlPort        TCP/IP port.  Ex: 80
737e76a69f 2009-03-30       drh: **   g.urlIsHttps     Use TLS for the connection
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: ** Return the number of errors.
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: int transport_open(void){
737e76a69f 2009-03-30       drh:   int rc = 0;
327823e39b 2009-03-30       drh:   if( transport.isOpen==0 ){
327823e39b 2009-03-30       drh:     if( g.urlIsHttps ){
327823e39b 2009-03-30       drh:       socket_set_errmsg("HTTPS: is not yet implemented");
327823e39b 2009-03-30       drh:       rc = 1;
327823e39b 2009-03-30       drh:     }else if( g.urlIsFile ){
945ecd1a8b 2009-04-11       drh:       sqlite3_uint64 iRandId;
945ecd1a8b 2009-04-11       drh:       sqlite3_randomness(sizeof(iRandId), &iRandId);
945ecd1a8b 2009-04-11       drh:       transport.zOutFile = mprintf("%s-%llu-out.http",
945ecd1a8b 2009-04-11       drh:                                        g.zRepositoryName, iRandId);
945ecd1a8b 2009-04-11       drh:       transport.zInFile = mprintf("%s-%llu-in.http",
945ecd1a8b 2009-04-11       drh:                                        g.zRepositoryName, iRandId);
945ecd1a8b 2009-04-11       drh:       transport.pFile = fopen(transport.zOutFile, "wb");
945ecd1a8b 2009-04-11       drh:       if( transport.pFile==0 ){
945ecd1a8b 2009-04-11       drh:         fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
945ecd1a8b 2009-04-11       drh:       }
945ecd1a8b 2009-04-11       drh:       transport.isOpen = 1;
327823e39b 2009-03-30       drh:     }else{
327823e39b 2009-03-30       drh:       rc = socket_open();
327823e39b 2009-03-30       drh:       if( rc==0 ) transport.isOpen = 1;
327823e39b 2009-03-30       drh:     }
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh:   return rc;
737e76a69f 2009-03-30       drh: }
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** Close the current connection
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: void transport_close(void){
737e76a69f 2009-03-30       drh:   if( transport.isOpen ){
737e76a69f 2009-03-30       drh:     free(transport.pBuf);
737e76a69f 2009-03-30       drh:     transport.pBuf = 0;
737e76a69f 2009-03-30       drh:     transport.nAlloc = 0;
737e76a69f 2009-03-30       drh:     transport.nUsed = 0;
737e76a69f 2009-03-30       drh:     transport.iCursor = 0;
327823e39b 2009-03-30       drh:     if( g.urlIsHttps ){
327823e39b 2009-03-30       drh:       /* TBD */
327823e39b 2009-03-30       drh:     }else if( g.urlIsFile ){
945ecd1a8b 2009-04-11       drh:       if( transport.pFile ){
945ecd1a8b 2009-04-11       drh:         fclose(transport.pFile);
945ecd1a8b 2009-04-11       drh:         transport.pFile = 0;
945ecd1a8b 2009-04-11       drh:       }
945ecd1a8b 2009-04-11       drh:       unlink(transport.zInFile);
945ecd1a8b 2009-04-11       drh:       unlink(transport.zOutFile);
a742cfa292 2009-04-11       drh:       free(transport.zInFile);
945ecd1a8b 2009-04-11       drh:       free(transport.zOutFile);
327823e39b 2009-03-30       drh:     }else{
327823e39b 2009-03-30       drh:       socket_close();
327823e39b 2009-03-30       drh:     }
327823e39b 2009-03-30       drh:     transport.isOpen = 0;
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh: }
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** Send content over the wire.
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: void transport_send(Blob *toSend){
737e76a69f 2009-03-30       drh:   char *z = blob_buffer(toSend);
737e76a69f 2009-03-30       drh:   int n = blob_size(toSend);
79be9028eb 2009-08-12       drh:   transport.nSent += n;
327823e39b 2009-03-30       drh:   if( g.urlIsHttps ){
327823e39b 2009-03-30       drh:     /* TBD */
327823e39b 2009-03-30       drh:   }else if( g.urlIsFile ){
945ecd1a8b 2009-04-11       drh:     fwrite(z, 1, n, transport.pFile);
945ecd1a8b 2009-04-11       drh:   }else{
327823e39b 2009-03-30       drh:     int sent;
327823e39b 2009-03-30       drh:     while( n>0 ){
327823e39b 2009-03-30       drh:       sent = socket_send(0, z, n);
767ae79c3d 2009-04-24       drh:       /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
327823e39b 2009-03-30       drh:       if( sent<=0 ) break;
327823e39b 2009-03-30       drh:       n -= sent;
327823e39b 2009-03-30       drh:     }
63ef585508 2009-03-30       drh:   }
63ef585508 2009-03-30       drh: }
63ef585508 2009-03-30       drh: 
63ef585508 2009-03-30       drh: /*
63ef585508 2009-03-30       drh: ** This routine is called when the outbound message is complete and
63ef585508 2009-03-30       drh: ** it is time to being recieving a reply.
63ef585508 2009-03-30       drh: */
63ef585508 2009-03-30       drh: void transport_flip(void){
63ef585508 2009-03-30       drh:   if( g.urlIsFile ){
945ecd1a8b 2009-04-11       drh:     char *zCmd;
945ecd1a8b 2009-04-11       drh:     fclose(transport.pFile);
945ecd1a8b 2009-04-11       drh:     zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1",
a742cfa292 2009-04-11       drh:        g.argv[0], g.urlName, transport.zOutFile, transport.zInFile
945ecd1a8b 2009-04-11       drh:     );
aeaee1f385 2009-09-10       drh:     portable_system(zCmd);
945ecd1a8b 2009-04-11       drh:     free(zCmd);
945ecd1a8b 2009-04-11       drh:     transport.pFile = fopen(transport.zInFile, "rb");
63ef585508 2009-03-30       drh:   }
63ef585508 2009-03-30       drh: }
63ef585508 2009-03-30       drh: 
63ef585508 2009-03-30       drh: /*
63ef585508 2009-03-30       drh: ** This routine is called when the inbound message has been received
63ef585508 2009-03-30       drh: ** and it is time to start sending again.
63ef585508 2009-03-30       drh: */
63ef585508 2009-03-30       drh: void transport_rewind(void){
63ef585508 2009-03-30       drh:   if( g.urlIsFile ){
63ef585508 2009-03-30       drh:     transport_close();
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh: }
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** Read N bytes of content from the wire and store in the supplied buffer.
737e76a69f 2009-03-30       drh: ** Return the number of bytes actually received.
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: int transport_receive(char *zBuf, int N){
737e76a69f 2009-03-30       drh:   int onHand;       /* Bytes current held in the transport buffer */
737e76a69f 2009-03-30       drh:   int nByte = 0;    /* Bytes of content received */
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh:   onHand = transport.nUsed - transport.iCursor;
737e76a69f 2009-03-30       drh:   if( onHand>0 ){
737e76a69f 2009-03-30       drh:     int toMove = onHand;
737e76a69f 2009-03-30       drh:     if( toMove>N ) toMove = N;
767ae79c3d 2009-04-24       drh:     /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
737e76a69f 2009-03-30       drh:     memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
737e76a69f 2009-03-30       drh:     transport.iCursor += toMove;
737e76a69f 2009-03-30       drh:     if( transport.iCursor>=transport.nUsed ){
737e76a69f 2009-03-30       drh:       transport.nUsed = 0;
737e76a69f 2009-03-30       drh:       transport.iCursor = 0;
737e76a69f 2009-03-30       drh:     }
737e76a69f 2009-03-30       drh:     N -= toMove;
737e76a69f 2009-03-30       drh:     zBuf += toMove;
737e76a69f 2009-03-30       drh:     nByte += toMove;
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh:   if( N>0 ){
327823e39b 2009-03-30       drh:     int got;
327823e39b 2009-03-30       drh:     if( g.urlIsHttps ){
327823e39b 2009-03-30       drh:       /* TBD */
327823e39b 2009-03-30       drh:       got = 0;
327823e39b 2009-03-30       drh:     }else if( g.urlIsFile ){
a742cfa292 2009-04-11       drh:       got = fread(zBuf, 1, N, transport.pFile);
327823e39b 2009-03-30       drh:     }else{
327823e39b 2009-03-30       drh:       got = socket_receive(0, zBuf, N);
767ae79c3d 2009-04-24       drh:       /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
327823e39b 2009-03-30       drh:     }
737e76a69f 2009-03-30       drh:     if( got>0 ){
737e76a69f 2009-03-30       drh:       nByte += got;
79be9028eb 2009-08-12       drh:       transport.nRcvd += got;
737e76a69f 2009-03-30       drh:     }
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh:   return nByte;
737e76a69f 2009-03-30       drh: }
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** Load up to N new bytes of content into the transport.pBuf buffer.
737e76a69f 2009-03-30       drh: ** The buffer itself might be moved.  And the transport.iCursor value
737e76a69f 2009-03-30       drh: ** might be reset to 0.
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: static void transport_load_buffer(int N){
737e76a69f 2009-03-30       drh:   int i, j;
737e76a69f 2009-03-30       drh:   if( transport.nAlloc==0 ){
737e76a69f 2009-03-30       drh:     transport.nAlloc = N;
737e76a69f 2009-03-30       drh:     transport.pBuf = malloc( N );
737e76a69f 2009-03-30       drh:     if( transport.pBuf==0 ) fossil_panic("out of memory");
737e76a69f 2009-03-30       drh:     transport.iCursor = 0;
737e76a69f 2009-03-30       drh:     transport.nUsed = 0;
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh:   if( transport.iCursor>0 ){
737e76a69f 2009-03-30       drh:     for(i=0, j=transport.iCursor; j<transport.nUsed; i++, j++){
737e76a69f 2009-03-30       drh:       transport.pBuf[i] = transport.pBuf[j];
737e76a69f 2009-03-30       drh:     }
737e76a69f 2009-03-30       drh:     transport.nUsed -= transport.iCursor;
737e76a69f 2009-03-30       drh:     transport.iCursor = 0;
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh:   if( transport.nUsed + N > transport.nAlloc ){
737e76a69f 2009-03-30       drh:     char *pNew;
737e76a69f 2009-03-30       drh:     transport.nAlloc = transport.nUsed + N;
737e76a69f 2009-03-30       drh:     pNew = realloc(transport.pBuf, transport.nAlloc);
737e76a69f 2009-03-30       drh:     if( pNew==0 ) fossil_panic("out of memory");
737e76a69f 2009-03-30       drh:     transport.pBuf = pNew;
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh:   if( N>0 ){
737e76a69f 2009-03-30       drh:     i = transport_receive(&transport.pBuf[transport.nUsed], N);
737e76a69f 2009-03-30       drh:     if( i>0 ){
737e76a69f 2009-03-30       drh:       transport.nUsed += i;
737e76a69f 2009-03-30       drh:     }
737e76a69f 2009-03-30       drh:   }
737e76a69f 2009-03-30       drh: }
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh: /*
737e76a69f 2009-03-30       drh: ** Fetch a single line of input where a line is all text up to the next
737e76a69f 2009-03-30       drh: ** \n character or until the end of input.  Remove all trailing whitespace
737e76a69f 2009-03-30       drh: ** from the received line and zero-terminate the result.  Return a pointer
737e76a69f 2009-03-30       drh: ** to the line.
737e76a69f 2009-03-30       drh: **
737e76a69f 2009-03-30       drh: ** Each call to this routine potentially overwrites the returned buffer.
737e76a69f 2009-03-30       drh: */
737e76a69f 2009-03-30       drh: char *transport_receive_line(void){
737e76a69f 2009-03-30       drh:   int i;
737e76a69f 2009-03-30       drh:   int iStart;
737e76a69f 2009-03-30       drh: 
737e76a69f 2009-03-30       drh:   i = iStart = transport.iCursor;
737e76a69f 2009-03-30       drh:   while(1){
737e76a69f 2009-03-30       drh:     if( i >= transport.nUsed ){
737e76a69f 2009-03-30       drh:       transport_load_buffer(1000);
737e76a69f 2009-03-30       drh:       i -= iStart;
737e76a69f 2009-03-30       drh:       iStart = 0;
737e76a69f 2009-03-30       drh:       if( i >= transport.nUsed ){
737e76a69f 2009-03-30       drh:         transport.pBuf[i] = 0;
737e76a69f 2009-03-30       drh:         transport.iCursor = i;
737e76a69f 2009-03-30       drh:         break;
737e76a69f 2009-03-30       drh:       }
737e76a69f 2009-03-30       drh:     }
737e76a69f 2009-03-30       drh:     if( transport.pBuf[i]=='\n' ){
737e76a69f 2009-03-30       drh:       transport.iCursor = i+1;
737e76a69f 2009-03-30       drh:       while( i>=iStart && isspace(transport.pBuf[i]) ){
737e76a69f 2009-03-30       drh:         transport.pBuf[i] = 0;
737e76a69f 2009-03-30       drh:         i--;
737e76a69f 2009-03-30       drh:       }
737e76a69f 2009-03-30       drh:       break;
737e76a69f 2009-03-30       drh:     }
737e76a69f 2009-03-30       drh:     i++;
737e76a69f 2009-03-30       drh:   }
767ae79c3d 2009-04-24       drh:   /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
737e76a69f 2009-03-30       drh:   return &transport.pBuf[iStart];
737e76a69f 2009-03-30       drh: }