Fossil

Check-in [8028c868d3]
Login

Check-in [8028c868d3]

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

Overview
Comment:The "ssh:"-style requests are eating the query parameters, somewhere. I don't know where yet. Don't use query parameter for the time being.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | get-command
Files: files | file ages | folders
SHA3-256: 8028c868d3c0551d4b3ba766e354b22d12bd64aba38f045cc701a0c93078f55a
User & Date: drh 2025-10-15 20:12:39.831
Context
2025-10-15
21:33
Fix CGI processing so that requests sent over SSH process query parameters. Add the --ssh-sim option to the test-http command (used to debug the previous). Harden the "fossil get" command so that it can checks filenames and does not write a file that is outside of the designated --dest. ... (check-in: 9a76760178 user: drh tags: get-command)
20:12
The "ssh:"-style requests are eating the query parameters, somewhere. I don't know where yet. Don't use query parameter for the time being. ... (check-in: 8028c868d3 user: drh tags: get-command)
17:15
Implement the "fossil get" command. ... (check-in: 552eee775a user: drh tags: get-command)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/checkout.c.
464
465
466
467
468
469
470

471

472
473
474
475
476
477
478
479
480
481
482



483
484
485
486
487
488
489
**                            than unpacking them into separate files.
**
**   -v|--verbose             Show all files as they are extracted
*/
void get_cmd(void){
  int forceFlag = find_option("force","f",0)!=0;
  int bVerbose = find_option("verbose","v",0)!=0;

  int bDebug = find_option("debug",0,0)!=0;

  const char *zSqlArchive = find_option("sqlar",0,1);
  const char *z;
  char *zDest = 0;        /* Where to store results */
  const char *zUrl;       /* Url to get */
  const char *zVers;      /* Version name to get */
  unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS;
  Blob in, out;           /* I/O for the HTTP request */
  Blob file;              /* A file to extract */
  sqlite3 *db;            /* Database containing downloaded sqlar */
  sqlite3_stmt *pStmt;    /* Statement for querying the database */
  int rc;                 /* Result of subroutine calls */




  z = find_option("dest",0,1);
  if( z ) zDest = fossil_strdup(z);
  verify_all_options();
  if( g.argc<3 || g.argc>4 ){
    usage("get URL ?VERSION? ?OPTIONS?");
  }







>

>











>
>
>







464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
**                            than unpacking them into separate files.
**
**   -v|--verbose             Show all files as they are extracted
*/
void get_cmd(void){
  int forceFlag = find_option("force","f",0)!=0;
  int bVerbose = find_option("verbose","v",0)!=0;
  int bQuiet = find_option("quiet","q",0)!=0;
  int bDebug = find_option("debug",0,0)!=0;
  int bList = find_option("list",0,0)!=0;
  const char *zSqlArchive = find_option("sqlar",0,1);
  const char *z;
  char *zDest = 0;        /* Where to store results */
  const char *zUrl;       /* Url to get */
  const char *zVers;      /* Version name to get */
  unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS;
  Blob in, out;           /* I/O for the HTTP request */
  Blob file;              /* A file to extract */
  sqlite3 *db;            /* Database containing downloaded sqlar */
  sqlite3_stmt *pStmt;    /* Statement for querying the database */
  int rc;                 /* Result of subroutine calls */
  int nFile = 0;          /* Number of files written */
  int nDir = 0;           /* Number of directories written */
  i64 nByte = 0;          /* Number of bytes written */

  z = find_option("dest",0,1);
  if( z ) zDest = fossil_strdup(z);
  verify_all_options();
  if( g.argc<3 || g.argc>4 ){
    usage("get URL ?VERSION? ?OPTIONS?");
  }
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551

552
553
554
555
556
557
558
        fossil_fatal("\"%s\" already exists", zDest);
      }
    }
  }

  /* Construct a subpath on the URL if necessary */
  if( g.url.isSsh || g.url.isFile ){
    g.url.subpath = mprintf("/sqlar?name=%t&r=%t", zDest, zVers);
  }

  if( bDebug ){
    urlparse_print(0);
  }

  /* Fetch the ZIP archive for the requested check-in */
  blob_init(&in, 0, 0);
  blob_init(&out, 0, 0);
  if( bDebug ) mHttpFlags |= HTTP_VERBOSE;

  http_exchange(&in, &out, mHttpFlags, 4, 0);

  if( zSqlArchive ){
    blob_write_to_file(&out, zSqlArchive);
    if( bVerbose ) fossil_print("%s\n", zSqlArchive);
    return;
  }







|










>







539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
        fossil_fatal("\"%s\" already exists", zDest);
      }
    }
  }

  /* Construct a subpath on the URL if necessary */
  if( g.url.isSsh || g.url.isFile ){
    g.url.subpath = mprintf("/sqlar/%t/%t.sqlar", zVers, zDest);
  }

  if( bDebug ){
    urlparse_print(0);
  }

  /* Fetch the ZIP archive for the requested check-in */
  blob_init(&in, 0, 0);
  blob_init(&out, 0, 0);
  if( bDebug ) mHttpFlags |= HTTP_VERBOSE;
  if( bQuiet ) mHttpFlags |= HTTP_QUIET;
  http_exchange(&in, &out, mHttpFlags, 4, 0);

  if( zSqlArchive ){
    blob_write_to_file(&out, zSqlArchive);
    if( bVerbose ) fossil_print("%s\n", zSqlArchive);
    return;
  }
574
575
576
577
578
579
580


581
582

583
584
585
586
587
588


589
590
591
592
593
594
595
    fossil_fatal("SQL error: %s\n", sqlite3_errmsg(db));
  }
  blob_init(&file, 0, 0);
  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    const char *zFilename = (const char*)sqlite3_column_text(pStmt, 0);
    int mode = sqlite3_column_int(pStmt, 1);
    int sz = sqlite3_column_int(pStmt, 2);


    if( mode & 0x4000 ){
      /* A directory name */

      file_mkdir(zFilename, ExtFILE, 1);
    }else{
      /* A file */
      unsigned char *inBuf = (unsigned char*)sqlite3_column_blob(pStmt,3);
      unsigned int nIn = (unsigned int)sqlite3_column_bytes(pStmt,3);
      unsigned long int nOut2 = (unsigned long int)sz;


      blob_resize(&file, sz);
      if( nIn<sz ){
        rc = uncompress((unsigned char*)blob_buffer(&file), &nOut2,
                        inBuf, nIn);
        if( rc!=Z_OK ){
          fossil_fatal("Failed to uncompress file %s", zFilename);
        }







>
>
|

>






>
>







580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
    fossil_fatal("SQL error: %s\n", sqlite3_errmsg(db));
  }
  blob_init(&file, 0, 0);
  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    const char *zFilename = (const char*)sqlite3_column_text(pStmt, 0);
    int mode = sqlite3_column_int(pStmt, 1);
    int sz = sqlite3_column_int(pStmt, 2);
    if( bList ){
      fossil_print("%s\n", zFilename);
    }else if( mode & 0x4000 ){
      /* A directory name */
      nDir++;
      file_mkdir(zFilename, ExtFILE, 1);
    }else{
      /* A file */
      unsigned char *inBuf = (unsigned char*)sqlite3_column_blob(pStmt,3);
      unsigned int nIn = (unsigned int)sqlite3_column_bytes(pStmt,3);
      unsigned long int nOut2 = (unsigned long int)sz;
      nFile++;
      nByte += sz;
      blob_resize(&file, sz);
      if( nIn<sz ){
        rc = uncompress((unsigned char*)blob_buffer(&file), &nOut2,
                        inBuf, nIn);
        if( rc!=Z_OK ){
          fossil_fatal("Failed to uncompress file %s", zFilename);
        }
605
606
607
608
609
610
611







612


        fossil_print("%s\n", zFilename);
      }
    }
  }
  sqlite3_finalize(pStmt);
  sqlite3_close(db);
  blob_zero(&out);







}









>
>
>
>
>
>
>
|
>
>
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
        fossil_print("%s\n", zFilename);
      }
    }
  }
  sqlite3_finalize(pStmt);
  sqlite3_close(db);
  blob_zero(&out);
  if( !bVerbose && !bQuiet && nFile>0 && zDest ){
    fossil_print("%d files (%,lld bytes) written into %s",
                 nFile, nByte, zDest);
    if( nDir>1 ){
      fossil_print(" and %d subdirectories\n", nDir-1);
    }else{
      fossil_print("\n");
    }
  }
}
Changes to src/http.c.
684
685
686
687
688
689
690

691
692
693
694
695
696

697
698
699
700
701
702
703
    */
    if( g.url.isSsh                         /* This is an SSH: sync */
     && (g.url.flags & URL_SSH_EXE)==0      /* Does not have ?fossil=.... */
     && (g.url.flags & URL_SSH_RETRY)==0    /* Not retried already */
    ){
      /* Retry after flipping the SSH_PATH setting */
      transport_close(&g.url);

      fossil_print(
        "First attempt to run fossil on %s using SSH failed.\n"
        "Retrying %s the PATH= argument.\n",
        g.url.hostname,
        (g.url.flags & URL_SSH_PATH)!=0 ? "without" : "with"
      );

      g.url.flags ^= URL_SSH_PATH|URL_SSH_RETRY;
      rc = http_exchange(pSend,pReply,mHttpFlags,0,zAltMimetype);
      if( rc==0 && g.db!=0 ){
        (void)ssh_needs_path_argument(g.url.hostname,
                                (g.url.flags & URL_SSH_PATH)!=0);
      }
      return rc;







>
|
|
|
|
|
|
>







684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
    */
    if( g.url.isSsh                         /* This is an SSH: sync */
     && (g.url.flags & URL_SSH_EXE)==0      /* Does not have ?fossil=.... */
     && (g.url.flags & URL_SSH_RETRY)==0    /* Not retried already */
    ){
      /* Retry after flipping the SSH_PATH setting */
      transport_close(&g.url);
      if( (mHttpFlags & HTTP_QUIET)==0 ){
        fossil_print(
          "First attempt to run fossil on %s using SSH failed.\n"
          "Retrying %s the PATH= argument.\n",
          g.url.hostname,
          (g.url.flags & URL_SSH_PATH)!=0 ? "without" : "with"
        );
      }
      g.url.flags ^= URL_SSH_PATH|URL_SSH_RETRY;
      rc = http_exchange(pSend,pReply,mHttpFlags,0,zAltMimetype);
      if( rc==0 && g.db!=0 ){
        (void)ssh_needs_path_argument(g.url.hostname,
                                (g.url.flags & URL_SSH_PATH)!=0);
      }
      return rc;