Fossil

Check-in [780d3b2fe3]
Login

Check-in [780d3b2fe3]

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

Overview
Comment:Previous checkin should not have compiled - clean rebuild uncovered a stale dep. Re-map the fLoginCardMode to a bitmask so that it's possible to tell when multiple paths toggle that on, and which paths they were.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | xfer-login-card
Files: files | file ages | folders
SHA3-256: 780d3b2fe3234fa3031f7087219334e5a9d20f11f4e05e804be11317b3b784ce
User & Date: stephan 2025-07-24 03:16:59.357
Context
2025-07-24
05:10
Use a Cookie, instead of a custom HTTP header and/or URL param, to send the sync login header, as suggested in [forum:9959d2d9d9be22d2 | forum post 9959d2d9d9be22d2]. This is simpler. ... (check-in: 756ad2f23c user: stephan tags: xfer-login-card)
03:16
Previous checkin should not have compiled - clean rebuild uncovered a stale dep. Re-map the fLoginCardMode to a bitmask so that it's possible to tell when multiple paths toggle that on, and which paths they were. ... (check-in: 780d3b2fe3 user: stephan tags: xfer-login-card)
03:03
Doc touchups. ... (check-in: aa36afc52c user: stephan tags: xfer-login-card)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/cgi.c.
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
    if( !g.syncInfo.zLoginCard && 0!=(z=(char*)P("x-f-x-l")) ){
      /* CGI fossil instances do not read the HTTP headers, so
      ** they cannot see the X-Fossil-Xfer-Login card. As a consolation
      ** to them, we'll accept that via this query argument. */
      rc |= 0x04;
      fossil_free( g.syncInfo.zLoginCard );
      g.syncInfo.zLoginCard = fossil_strdup(z);
      g.syncInfo.fLoginCardMode = 3;
      cgi_delete_parameter("x-f-x-l");
    }
  }
  return rc;
}

/*







|







1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
    if( !g.syncInfo.zLoginCard && 0!=(z=(char*)P("x-f-x-l")) ){
      /* CGI fossil instances do not read the HTTP headers, so
      ** they cannot see the X-Fossil-Xfer-Login card. As a consolation
      ** to them, we'll accept that via this query argument. */
      rc |= 0x04;
      fossil_free( g.syncInfo.zLoginCard );
      g.syncInfo.zLoginCard = fossil_strdup(z);
      g.syncInfo.fLoginCardMode |= 0x10;
      cgi_delete_parameter("x-f-x-l");
    }
  }
  return rc;
}

/*
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
      if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){
        rangeStart = x1;
        rangeEnd = x2+1;
      }
    }else if( fossil_strcmp(zFieldName, "x-fossil-xfer-login:")==0 ){
      fossil_free( g.syncInfo.zLoginCard );
      g.syncInfo.zLoginCard = fossil_strdup(zVal);
      g.syncInfo.fLoginCardMode = 1;
    }
  }
  cgi_setenv("REQUEST_SCHEME",zScheme);
  cgi_init();
  cgi_trace(0);
}








|







2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
      if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){
        rangeStart = x1;
        rangeEnd = x2+1;
      }
    }else if( fossil_strcmp(zFieldName, "x-fossil-xfer-login:")==0 ){
      fossil_free( g.syncInfo.zLoginCard );
      g.syncInfo.zLoginCard = fossil_strdup(zVal);
      g.syncInfo.fLoginCardMode |= 0x08;
    }
  }
  cgi_setenv("REQUEST_SCHEME",zScheme);
  cgi_init();
  cgi_trace(0);
}

Changes to src/http.c.
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
    char * z = g.url.path;
    while( z && *z && '?'!=*z ) ++z;
    if( z && *z ) *z = 0;
    x = mprintf("%s?x-f-x-l=%T", g.url.path ? g.url.path : "/",
                blob_str(pLogin));
    fossil_free(g.url.path);
    g.url.path = x;
    if( !g.syncInfo.fLoginCardMode ){
      g.syncInfo.fLoginCardMode = 4;
    }
  }
}

/*
** Construct an appropriate HTTP request header.  Write the header
** into pHdr.  This routine initializes the pHdr blob.  pPayload is
** the complete payload (including the login card if pLogin is NULL or







<
|
<







145
146
147
148
149
150
151

152

153
154
155
156
157
158
159
    char * z = g.url.path;
    while( z && *z && '?'!=*z ) ++z;
    if( z && *z ) *z = 0;
    x = mprintf("%s?x-f-x-l=%T", g.url.path ? g.url.path : "/",
                blob_str(pLogin));
    fossil_free(g.url.path);
    g.url.path = x;

    g.syncInfo.fLoginCardMode |= 0x04;

  }
}

/*
** Construct an appropriate HTTP request header.  Write the header
** into pHdr.  This routine initializes the pHdr blob.  pPayload is
** the complete payload (including the login card if pLogin is NULL or
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  }
  /* Construct the login card and prepare the complete payload */
  blob_zero(&login);
  if( blob_size(pSend)==0 ){
    blob_zero(&payload);
  }else{
    if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
    if( g.syncInfo.fLoginCardMode>0 ){
      /* The login card will be sent via an HTTP header and/or URL flag. */
      if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
        /* Maintenance note: we cannot blob_swap(pSend,&payload) here
        ** because the HTTP 401 and redirect response handling below
        ** needs pSend unmodified. payload won't be modified after
        ** this point, so we can make it a proxy for pSend for
        ** zero heap memory. */







|







499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  }
  /* Construct the login card and prepare the complete payload */
  blob_zero(&login);
  if( blob_size(pSend)==0 ){
    blob_zero(&payload);
  }else{
    if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
    if( g.syncInfo.fLoginCardMode ){
      /* The login card will be sent via an HTTP header and/or URL flag. */
      if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
        /* Maintenance note: we cannot blob_swap(pSend,&payload) here
        ** because the HTTP 401 and redirect response handling below
        ** needs pSend unmodified. payload won't be modified after
        ** this point, so we can make it a proxy for pSend for
        ** zero heap memory. */
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
        }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
          isError = 1;
        }
      }
    }else if( fossil_strnicmp(zLine, "x-fossil-xfer-login: ", 21)==0 ){
      fossil_free( g.syncInfo.zLoginCard );
      g.syncInfo.zLoginCard = fossil_strdup(&zLine[21]);
      g.syncInfo.fLoginCardMode = 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.







|







692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
        }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
          isError = 1;
        }
      }
    }else if( fossil_strnicmp(zLine, "x-fossil-xfer-login: ", 21)==0 ){
      fossil_free( g.syncInfo.zLoginCard );
      g.syncInfo.zLoginCard = fossil_strdup(&zLine[21]);
      g.syncInfo.fLoginCardMode |= 0x02;
    }
  }
  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.
Changes to src/main.c.
297
298
299
300
301
302
303
304
305
306



307
308
309
310
311
312
313
    char *zLoginCard;       /* Inbound "X-Fossil-Xfer-Login" request
                            ** header or "x-f-x-l" URL parameter. */
    int fLoginCardMode;     /* If non-0, emit login cards in outbound
                            ** requests as a HTTP header or URL
                            ** parameter instead of as part of the
                            ** payload. Gets activated on-demand based
                            ** on xfer traffic contents. Values, for
                            ** diagnostic/debugging purposes: 1=CLI
                            ** --flag. 2=inbound HTTP header. 3=query
                            ** string arg. 4=http_build_header(). */



    int remoteVersion;      /* Remote fossil version. Used for negotiating
                            ** how to handle the login card. */
  } syncInfo;
#ifdef FOSSIL_ENABLE_JSON
  struct FossilJsonBits {
    int isJsonMode;            /* True if running in JSON mode, else
                                  false. This changes how errors are







|
|
|
>
>
>







297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
    char *zLoginCard;       /* Inbound "X-Fossil-Xfer-Login" request
                            ** header or "x-f-x-l" URL parameter. */
    int fLoginCardMode;     /* If non-0, emit login cards in outbound
                            ** requests as a HTTP header or URL
                            ** parameter instead of as part of the
                            ** payload. Gets activated on-demand based
                            ** on xfer traffic contents. Values, for
                            ** diagnostic/debugging purposes: 0x01=CLI
                            ** --flag, 0x02=http_exchange(),
                            ** 0x04=url_append_login_card(),
                            ** 0x08=cgi_handle_cgi_request(),
                            ** 0x10=cgi_setup_query_string(),
                            ** 0x20=page_xfer(), 0x40=client_sync(). */
    int remoteVersion;      /* Remote fossil version. Used for negotiating
                            ** how to handle the login card. */
  } syncInfo;
#ifdef FOSSIL_ENABLE_JSON
  struct FossilJsonBits {
    int isJsonMode;            /* True if running in JSON mode, else
                                  false. This changes how errors are
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
#endif
  g.mainTimerId = fossil_timer_start();
  capture_case_sensitive_option();
  g.syncInfo.fLoginCardMode =
    /* This is only for facilitating development of the
    ** xfer-login-card branch. It will be removed or re-imagined at
    ** some point. */
    !!find_option("login-card-header","lch", 0);
  g.zVfsName = find_option("vfs",0,1);
  if( g.zVfsName==0 ){
    g.zVfsName = fossil_getenv("FOSSIL_VFS");
  }
  if( g.zVfsName ){
    sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName);
    if( pVfs ){







|







780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
#endif
  g.mainTimerId = fossil_timer_start();
  capture_case_sensitive_option();
  g.syncInfo.fLoginCardMode =
    /* This is only for facilitating development of the
    ** xfer-login-card branch. It will be removed or re-imagined at
    ** some point. */
    find_option("login-card-header","lch", 0) ? 0x01 : 0;
  g.zVfsName = find_option("vfs",0,1);
  if( g.zVfsName==0 ){
    g.zVfsName = fossil_getenv("FOSSIL_VFS");
  }
  if( g.zVfsName ){
    sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName);
    if( pVfs ){
Changes to src/xfer.c.
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
  if( zScript ){ /* NOTE: Are TH1 transfer hooks enabled? */
    pzUuidList = &zUuidList;
    pnUuidList = &nUuidList;
  }
  if( g.syncInfo.zLoginCard ){
    /* Login card received via HTTP header "X-Fossil-Xfer-Login" or
    ** "x-f-x-l" URL parameter. */
    assert( g.syncInfo.bLoginCardHeader && "Set via HTTP header/URL arg" );
    blob_zero(&xfer.line);
    blob_append(&xfer.line, g.syncInfo.zLoginCard, -1);
    xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken,
                                count(xfer.aToken));
    fossil_free( g.syncInfo.zLoginCard );
    g.syncInfo.zLoginCard = 0;
    if( xfer.nToken==4







|







1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
  if( zScript ){ /* NOTE: Are TH1 transfer hooks enabled? */
    pzUuidList = &zUuidList;
    pnUuidList = &nUuidList;
  }
  if( g.syncInfo.zLoginCard ){
    /* Login card received via HTTP header "X-Fossil-Xfer-Login" or
    ** "x-f-x-l" URL parameter. */
    assert( g.syncInfo.fLoginCardMode && "Set via HTTP header/URL arg" );
    blob_zero(&xfer.line);
    blob_append(&xfer.line, g.syncInfo.zLoginCard, -1);
    xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken,
                                count(xfer.aToken));
    fossil_free( g.syncInfo.zLoginCard );
    g.syncInfo.zLoginCard = 0;
    if( xfer.nToken==4
1720
1721
1722
1723
1724
1725
1726
1727
1728


1729
1730
1731
1732
1733
1734
1735
      ** The client announces to the server what version of Fossil it
      ** is running.  The DATE and TIME are a pure numeric ISO8601 time
      ** for the specific check-in of the client.
      */
      if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
        xfer.remoteVersion = g.syncInfo.remoteVersion =
          atoi(blob_str(&xfer.aToken[2]));
        g.syncInfo.bLoginCardHeader =
          xfer.remoteVersion>=RELEASE_VERSION_NUMBER;


        if( xfer.nToken>=5 ){
          xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
          xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
          @ pragma server-version %d(RELEASE_VERSION_NUMBER) \
          @ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
        }
      }else







<
|
>
>







1720
1721
1722
1723
1724
1725
1726

1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
      ** The client announces to the server what version of Fossil it
      ** is running.  The DATE and TIME are a pure numeric ISO8601 time
      ** for the specific check-in of the client.
      */
      if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
        xfer.remoteVersion = g.syncInfo.remoteVersion =
          atoi(blob_str(&xfer.aToken[2]));

        if( xfer.remoteVersion>=RELEASE_VERSION_NUMBER ){
          g.syncInfo.fLoginCardMode |= 0x20;
        }
        if( xfer.nToken>=5 ){
          xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
          xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
          @ pragma server-version %d(RELEASE_VERSION_NUMBER) \
          @ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
        }
      }else
2782
2783
2784
2785
2786
2787
2788
2789
2790


2791
2792
2793
2794
2795
2796
2797
        ** The server announces to the server what version of Fossil it
        ** is running.  The DATE and TIME are a pure numeric ISO8601 time
        ** for the specific check-in of the client.
        */
        if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
          xfer.remoteVersion = g.syncInfo.remoteVersion =
            atoi(blob_str(&xfer.aToken[2]));
          g.syncInfo.bLoginCardHeader =
            xfer.remoteVersion>=RELEASE_VERSION_NUMBER;


          if( xfer.nToken>=5 ){
            xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
            xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
          }
        }

        /*   pragma uv-pull-only







<
|
>
>







2783
2784
2785
2786
2787
2788
2789

2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
        ** The server announces to the server what version of Fossil it
        ** is running.  The DATE and TIME are a pure numeric ISO8601 time
        ** for the specific check-in of the client.
        */
        if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
          xfer.remoteVersion = g.syncInfo.remoteVersion =
            atoi(blob_str(&xfer.aToken[2]));

          if( xfer.remoteVersion>=RELEASE_VERSION_NUMBER ){
            g.syncInfo.fLoginCardMode |= 0x40;
          }
          if( xfer.nToken>=5 ){
            xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
            xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
          }
        }

        /*   pragma uv-pull-only