Fossil

Check-in [dfefd069]
Login

Check-in [dfefd069]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Arrange for the HTTP reply parser to be able to deal with a missing Content-Length header. Add the --xverbose option to the "fossil clone" command.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | content-length-errors
Files: files | file ages | folders
SHA3-256: dfefd069b6026effb244718496a6d2d4b8dd820ad1b5ad025886e52e5e093516
User & Date: drh 2024-04-17 12:18:22
Context
2024-04-17
12:49
Fix ssh: clones, broken by the previous check-in. ... (Closed-Leaf check-in: de647e86 user: drh tags: content-length-errors)
12:18
Arrange for the HTTP reply parser to be able to deal with a missing Content-Length header. Add the --xverbose option to the "fossil clone" command. ... (check-in: dfefd069 user: drh tags: content-length-errors)
2024-04-16
22:55
Attempt to provide more useful error messages when an intermediate server (such as Apache) does something wrong and messes up an HTTP request. ... (check-in: 131ba0fa user: drh tags: content-length-errors)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/clone.c.

134
135
136
137
138
139
140

141
142
143
144
145
146
147
**    --save-http-password       Remember the HTTP password without asking
**    -c|--ssh-command SSH       Use SSH as the "ssh" command
**    --ssl-identity FILENAME    Use the SSL identity if requested by the server
**    --transport-command CMD    Use CMD to move messages to the server and back
**    -u|--unversioned           Also sync unversioned content
**    -v|--verbose               Show more statistics in output
**    --workdir DIR              Also open a check-out in DIR

**
** See also: [[init]], [[open]]
*/
void clone_cmd(void){
  char *zPassword;
  const char *zDefaultUser;   /* Optional name of the default user */
  const char *zHttpAuth;      /* HTTP Authorization user:pass information */







>







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
**    --save-http-password       Remember the HTTP password without asking
**    -c|--ssh-command SSH       Use SSH as the "ssh" command
**    --ssl-identity FILENAME    Use the SSL identity if requested by the server
**    --transport-command CMD    Use CMD to move messages to the server and back
**    -u|--unversioned           Also sync unversioned content
**    -v|--verbose               Show more statistics in output
**    --workdir DIR              Also open a check-out in DIR
**    --xverbose                 Extra debugging output
**
** See also: [[init]], [[open]]
*/
void clone_cmd(void){
  char *zPassword;
  const char *zDefaultUser;   /* Optional name of the default user */
  const char *zHttpAuth;      /* HTTP Authorization user:pass information */
159
160
161
162
163
164
165

166
167
168
169
170
171
172
  if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
  if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
  if( find_option("save-http-password",0,0)!=0 ){
    urlFlags &= ~URL_PROMPT_PW;
    urlFlags |= URL_REMEMBER_PW;
  }
  if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;

  if( find_option("unversioned","u",0)!=0 ){
    syncFlags |= SYNC_UNVERSIONED;
    if( syncFlags & SYNC_VERBOSE ){
      syncFlags |= SYNC_UV_TRACE;
    }
  }
  zHttpAuth = find_option("httpauth","B",1);







>







160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
  if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
  if( find_option("save-http-password",0,0)!=0 ){
    urlFlags &= ~URL_PROMPT_PW;
    urlFlags |= URL_REMEMBER_PW;
  }
  if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
  if( find_option("xverbose",0,0)!=0) syncFlags |= SYNC_XVERBOSE;
  if( find_option("unversioned","u",0)!=0 ){
    syncFlags |= SYNC_UNVERSIONED;
    if( syncFlags & SYNC_VERBOSE ){
      syncFlags |= SYNC_UV_TRACE;
    }
  }
  zHttpAuth = find_option("httpauth","B",1);

Changes to src/http.c.

434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  const char *zAltMimetype    /* Alternative mimetype if not NULL */
){
  Blob login;           /* The login card */
  Blob payload;         /* The complete payload including login card */
  Blob hdr;             /* The HTTP request header */
  int closeConnection;  /* True to close the connection when done */
  int iLength;          /* Expected length of the reply payload */
  int iRecvLen;         /* Received length of the reply payload */
  int rc = 0;           /* Result code */
  int iHttpVersion;     /* Which version of HTTP protocol server uses */
  char *zLine;          /* A single line of the reply header */
  int i;                /* Loop counter */
  int isError = 0;      /* True if the reply is an error message */
  int isCompressed = 1; /* True if the reply is compressed */








<







434
435
436
437
438
439
440

441
442
443
444
445
446
447
  const char *zAltMimetype    /* Alternative mimetype if not NULL */
){
  Blob login;           /* The login card */
  Blob payload;         /* The complete payload including login card */
  Blob hdr;             /* The HTTP request header */
  int closeConnection;  /* True to close the connection when done */
  int iLength;          /* Expected length of the reply payload */

  int rc = 0;           /* Result code */
  int iHttpVersion;     /* Which version of HTTP protocol server uses */
  char *zLine;          /* A single line of the reply header */
  int i;                /* Loop counter */
  int isError = 0;      /* True if the reply is an error message */
  int isCompressed = 1; /* True if the reply is compressed */

523
524
525
526
527
528
529

530
531
532
533
534
535
536
  transport_flip(&g.url);

  /*
  ** Read and interpret the server reply
  */
  closeConnection = 1;
  iLength = -1;

  while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
    if( mHttpFlags & HTTP_VERBOSE ){
      fossil_print("Read: [%s]\n", zLine);
    }
    if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
      if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
      if( rc==401 ){







>







522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  transport_flip(&g.url);

  /*
  ** Read and interpret the server reply
  */
  closeConnection = 1;
  iLength = -1;
  iHttpVersion = -1;
  while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
    if( mHttpFlags & HTTP_VERBOSE ){
      fossil_print("Read: [%s]\n", zLine);
    }
    if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
      if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
      if( rc==401 ){
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
          if( mHttpFlags & HTTP_NOCOMPRESS ) isCompressed = 0;
        }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
          isError = 1;
        }
      }
    }
  }
  if( iLength<0 ){
    /* We got nothing back from the server.  If using the ssh: protocol,
    ** this might mean we need to add or remove the PATH=... argument
    ** to the SSH command being sent.  If that is the case, retry the
    ** request after adding or removing the PATH= argument.
    */
    if( g.url.isSsh                         /* This is an SSH: sync */
     && (g.url.flags & URL_SSH_EXE)==0      /* Does not have ?fossil=.... */







|







634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
          if( mHttpFlags & HTTP_NOCOMPRESS ) isCompressed = 0;
        }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
          isError = 1;
        }
      }
    }
  }
  if( iHttpVersion<0 ){
    /* We got nothing back from the server.  If using the ssh: protocol,
    ** this might mean we need to add or remove the PATH=... argument
    ** to the SSH command being sent.  If that is the case, retry the
    ** request after adding or removing the PATH= argument.
    */
    if( g.url.isSsh                         /* This is an SSH: sync */
     && (g.url.flags & URL_SSH_EXE)==0      /* Does not have ?fossil=.... */
680
681
682
683
684
685
686





687
688



689
690

691
692







693








694
695
696
697
698
699
700
    goto write_err;
  }

  /*
  ** Extract the reply payload that follows the header
  */
  blob_zero(pReply);





  blob_resize(pReply, iLength);
  iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength);



  if( iRecvLen != iLength ){
    fossil_warning("response truncated: got %d bytes of %d", iRecvLen, iLength);

    goto write_err;
  }







  blob_resize(pReply, iLength);








  if( isError ){
    char *z;
    int i, j;
    z = blob_str(pReply);
    for(i=j=0; z[i]; i++, j++){
      if( z[i]=='<' ){
        while( z[i] && z[i]!='>' ) i++;







>
>
>
>
>
|
|
>
>
>
|
|
>
|
|
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>







680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
    goto write_err;
  }

  /*
  ** Extract the reply payload that follows the header
  */
  blob_zero(pReply);
  if( iLength==0 ){
    /* No content to read */
  }else if( iLength>0 ){
    /* Read content of a known length */
    int iRecvLen;         /* Received length of the reply payload */
    blob_resize(pReply, iLength);
    iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength);
    if( mHttpFlags & HTTP_VERBOSE ){
      fossil_print("Reply received: %d of %d bytes\n", iRecvLen, iLength);
    }
    if( iRecvLen != iLength ){
      fossil_warning("response truncated: got %d bytes of %d",
                     iRecvLen, iLength);
      goto write_err;
    }
  }else{
    /* Read content until end-of-file */
    int iRecvLen;         /* Received length of the reply payload */
    unsigned int nReq = 1000;
    unsigned int nPrior = 0;
    do{
      nReq *= 2;
      blob_resize(pReply, nPrior+nReq);
      iRecvLen = transport_receive(&g.url, &pReply->aData[nPrior], (int)nReq);
      nPrior += iRecvLen;
      pReply->nUsed = nPrior;
    }while( iRecvLen==nReq && nReq<0x20000000 );
    if( mHttpFlags & HTTP_VERBOSE ){
      fossil_print("Reply received: %u bytes (w/o content-length)\n", nPrior);
    }
  }
  if( isError ){
    char *z;
    int i, j;
    z = blob_str(pReply);
    for(i=j=0; z[i]; i++, j++){
      if( z[i]=='<' ){
        while( z[i] && z[i]!='>' ) i++;