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

Overview
Comment:When accessing a remote repository, if there is a username/password specified as part of the URI, use these to login.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:3dcaed8d86cde74f050f862f0fc23cb7ea9cc0f1
User & Date: dan 2007-07-28 07:09:25
Context
2007-07-28
08:04
Remove a c++ism from deltacmd.c. check-in: 0c227fa4 user: dan tags: trunk
07:09
When accessing a remote repository, if there is a username/password specified as part of the URI, use these to login. check-in: 3dcaed8d user: dan tags: trunk
2007-07-24
18:15
File format document change: UUIDs use lowercase not uppercase hex. check-in: 01e7596a user: drh tags: trunk
Changes

Changes to src/db.c.

760
761
762
763
764
765
766































767
768
769
770
771
772
773
}
int db_lget_int(const char *zName, int dflt){
  return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
}
void db_lset_int(const char *zName, int value){
  db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
}
































/*
** COMMAND: open
**
** Create a new local repository.
*/
void cmd_open(void){







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
}
int db_lget_int(const char *zName, int dflt){
  return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
}
void db_lset_int(const char *zName, int value){
  db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
}

int db_row_to_table(const char *zFormat, ...){
  Stmt q;
  va_list ap;
  int rc;

  va_start(ap, zFormat);
  rc = db_vprepare(&q, zFormat, ap);
  va_end(ap);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  @ <table border="0" cellpadding="0" cellspacing="0">
  if( db_step(&q)==SQLITE_ROW ){
    int ii;
    for(ii=0; ii<sqlite3_column_count(q.pStmt); ii++){
      char *zCol = htmlize(sqlite3_column_name(q.pStmt, ii), -1);
      char *zVal = htmlize(sqlite3_column_text(q.pStmt, ii), -1);

      @ <tr><td align=right>%s(zCol):<td width=10><td>%s(zVal)

      free(zVal);
      free(zCol);
    }
  }
  @ </table>

  return db_finalize(&q);
}


/*
** COMMAND: open
**
** Create a new local repository.
*/
void cmd_open(void){

Changes to src/encode.c.

180
181
182
183
184
185
186




187
188
189
190
191
192
193

/*
** Remove the HTTP encodings from a string.  The conversion is done
** in-place.  Return the length of the string after conversion.
*/
int dehttpize(char *z){
  int i, j;




  i = j = 0;
  while( z[i] ){
    switch( z[i] ){
      case '%':
        if( z[i+1] && z[i+2] ){
          z[j] = AsciiToHex(z[i+1]) << 4;
          z[j] |= AsciiToHex(z[i+2]);







>
>
>
>







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

/*
** Remove the HTTP encodings from a string.  The conversion is done
** in-place.  Return the length of the string after conversion.
*/
int dehttpize(char *z){
  int i, j;

  /* Treat a null pointer as a zero-length string. */
  if( !z ) return 0;

  i = j = 0;
  while( z[i] ){
    switch( z[i] ){
      case '%':
        if( z[i+1] && z[i+2] ){
          z[j] = AsciiToHex(z[i+1]) << 4;
          z[j] |= AsciiToHex(z[i+2]);

Changes to src/http.c.

150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
165
166














167



168
169
170
171
172
173
174
175
176
177
** this routine is called - this routine will initialize it.
**
** The server address is contain in the "g" global structure.  The
** url_parse() routine should have been called prior to this routine
** in order to fill this structure appropriately.
*/
void http_exchange(Blob *pSend, Blob *pRecv){

  Blob login, nonce, sig, pw, payload, hdr;
  const char *zSep;
  int i;
  int cnt = 0;

  user_select();
  blob_zero(&nonce);
  blob_zero(&pw);
  db_blob(&nonce, "SELECT hex(randomblob(20))");
  blob_copy(&pw, &nonce);














  db_blob(&pw, "SELECT pw FROM user WHERE uid=%d", g.userUid);



  sha1sum_blob(&pw, &sig);
  blob_zero(&login);
  blob_appendf(&login, "login %s %b %b\n", g.zLogin, &nonce, &sig);
  blob_reset(&nonce);
  blob_reset(&pw);
  blob_reset(&sig);
  if( g.fHttpTrace ){
    payload = login;
    blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
  }else{







>





<




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


|







150
151
152
153
154
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
** this routine is called - this routine will initialize it.
**
** The server address is contain in the "g" global structure.  The
** url_parse() routine should have been called prior to this routine
** in order to fill this structure appropriately.
*/
void http_exchange(Blob *pSend, Blob *pRecv){
  const char *zLogin;              /* Username to send to server */ 
  Blob login, nonce, sig, pw, payload, hdr;
  const char *zSep;
  int i;
  int cnt = 0;


  blob_zero(&nonce);
  blob_zero(&pw);
  db_blob(&nonce, "SELECT hex(randomblob(20))");
  blob_copy(&pw, &nonce);

  if( g.urlUsername ){
    /* In this case, a username and optionally a password were specified 
    ** as part of the URI to contact. This overrides the default user 
    ** and -user option (if any). If no password was specified as part 
    ** of the URI, use an empty string ("") as the password.
    */
    blob_append(&pw, g.urlPassword ? g.urlPassword : "", -1);
    zLogin = g.urlUsername;
  }else{
    /* Otherwise, use either the default user or the user specified with
    ** the -user option. Pull the password from the local repository.
    */
    user_select();
    db_blob(&pw, "SELECT pw FROM user WHERE uid=%d", g.userUid);
    zLogin = g.zLogin;
  }

  sha1sum_blob(&pw, &sig);
  blob_zero(&login);
  blob_appendf(&login, "login %s %b %b\n", zLogin, &nonce, &sig);
  blob_reset(&nonce);
  blob_reset(&pw);
  blob_reset(&sig);
  if( g.fHttpTrace ){
    payload = login;
    blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
  }else{

Changes to src/info.c.

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
121
122
123
124
125
126
127











128



129
130
131
132
133
134
135
136
137
138
...
254
255
256
257
258
259
260

261

262
263
264
265
266
267
268
    if( rid==0 ){
      fossil_panic("no such object: %s\n", g.argv[2]);
    }
    show_common_info(rid, "uuid:", 1);
  }
}

#if 0
/*
** WEB PAGE: vinfo
**
** Return information about a version.  The version number is contained
** in g.zExtra.
*/
void vinfo_page(void){
  Stmt q;
  int rid;
................................................................................
  style_header("Version Information");
  rid = name_to_rid(g.zExtra);
  if( rid==0 ){
    @ No such object: %h(g.argv[2])
    style_footer();
    return;
  }











  db_prepare(&q,



    "SELECT uuid, datetime(mtime,'unixepoch'), datetime(ctime,'unixepoch'),"
    "         uid, size, cksum, branch, comment, type"
    "  FROM record WHERE rid=%d", rid
  );
  if( db_step(&q)==SQLITE_ROW ){
    const char *z;
    const char *zSignedBy = db_text("unknown",
                                     "SELECT login FROM repuser WHERE uid=%d",
                                     db_column_int(&q, 3));
    cType = db_column_text(&q,8)[0];
................................................................................
      hyperlink_to_uuid(zUuid);
      @ </td></tr>
    }
    db_finalize(&q);
  }
  style_footer();
}



/*
** WEB PAGE: diff
**
** Display the difference between two files determined by the v1 and v2
** query parameters.  If only v2 is given compute v1 as the parent of v2.
** If v2 has no parent, then show the complete text of v2.
*/







|

|







 







>
>
>
>
>
>
>
>
>
>
>

>
>
>
|
|
|







 







>

>







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
    if( rid==0 ){
      fossil_panic("no such object: %s\n", g.argv[2]);
    }
    show_common_info(rid, "uuid:", 1);
  }
}

#if 1
/*
** WEBPAGE: vinfo
**
** Return information about a version.  The version number is contained
** in g.zExtra.
*/
void vinfo_page(void){
  Stmt q;
  int rid;
................................................................................
  style_header("Version Information");
  rid = name_to_rid(g.zExtra);
  if( rid==0 ){
    @ No such object: %h(g.argv[2])
    style_footer();
    return;
  }
  db_row_to_table("SELECT "
    "  blob.uuid               AS \"UUID\""
    ", datetime(rcvfrom.mtime) AS \"Created\""
    ", rcvfrom.uid             AS \"User Id\""
    ", blob.size               AS \"Size\""
    "FROM blob, rcvfrom "
    "WHERE rid=%d", rid
  );
  style_footer();
  return;

  db_prepare(&q,
    "SELECT "
      "uuid, "                                         /* 0 */
      "datetime(mtime,'unixepoch'),"                   /* 1 */
      "datetime(ctime,'unixepoch'),"                   /* 2 */
      "uid, size, cksum, branch, comment, type"        /* 3..8 */
    "FROM record WHERE rid=%d", rid
  );
  if( db_step(&q)==SQLITE_ROW ){
    const char *z;
    const char *zSignedBy = db_text("unknown",
                                     "SELECT login FROM repuser WHERE uid=%d",
                                     db_column_int(&q, 3));
    cType = db_column_text(&q,8)[0];
................................................................................
      hyperlink_to_uuid(zUuid);
      @ </td></tr>
    }
    db_finalize(&q);
  }
  style_footer();
}
#endif

#if 0
/*
** WEB PAGE: diff
**
** Display the difference between two files determined by the v1 and v2
** query parameters.  If only v2 is given compute v1 as the parent of v2.
** If v2 has no parent, then show the complete text of v2.
*/

Changes to src/main.c.

68
69
70
71
72
73
74


75
76
77
78
79
80
81
  int cgiPanic;           /* Write error messages to CGI */

  int urlIsFile;          /* True if a "file:" url */
  char *urlName;          /* Hostname for http: or filename for file: */
  int urlPort;            /* TCP port number for http: */
  char *urlPath;          /* Pathname for http: */
  char *urlCanonical;     /* Canonical representation of the URL */



  const char *zLogin;     /* Login name.  "" if not logged in. */
  int isAnon;             /* True if logged in anoymously */
  int noPswd;             /* Logged in without password (on 127.0.0.1) */
  int userUid;            /* Integer user id */

  /* Information used to populate the RCVFROM table */







>
>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  int cgiPanic;           /* Write error messages to CGI */

  int urlIsFile;          /* True if a "file:" url */
  char *urlName;          /* Hostname for http: or filename for file: */
  int urlPort;            /* TCP port number for http: */
  char *urlPath;          /* Pathname for http: */
  char *urlCanonical;     /* Canonical representation of the URL */
  char *urlUsername;      /* Username specified as part of the URI */
  char *urlPassword;      /* Password specified as part of the URI */

  const char *zLogin;     /* Login name.  "" if not logged in. */
  int isAnon;             /* True if logged in anoymously */
  int noPswd;             /* Logged in without password (on 127.0.0.1) */
  int userUid;            /* Integer user id */

  /* Information used to populate the RCVFROM table */

Changes to src/url.c.

21
22
23
24
25
26
27
28

























































29















30
31
32
33
34
35
36
37










38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60


61
62
63
64
65
66
67
**
*******************************************************************************
**
** This file contains code for parsing URLs that appear on the command-line
*/
#include "config.h"
#include "url.h"


























































/*















** Parse the given URL.  Populate variables in the global "g" structure.
**
**      g.urlIsFile      True if this is a file URL
**      g.urlName        Hostname for HTTP:.  Filename for FILE:
**      g.urlPort        Port name for HTTP.
**      g.urlPath        Path name for HTTP.
**      g.urlCanonical   The URL in canonical form
**










*/
void url_parse(const char *zUrl){
  int i, j, c;
  char *zFile;
  if( strncmp(zUrl, "http:", 5)==0 ){
    g.urlIsFile = 0;
    for(i=7; (c=zUrl[i])!=0 && c!=':' && c!='/'; i++){}
    g.urlName = mprintf("%.*s", i-7, &zUrl[7]);
    for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); }
    if( c==':' ){
      g.urlPort = 0;
      i++;
      while( (c = zUrl[i])!=0 && isdigit(c) ){
        g.urlPort = g.urlPort*10 + c - '0';
        i++;
      }
    }else{
      g.urlPort = 80;
    }


    g.urlPath = mprintf(&zUrl[i]);
    dehttpize(g.urlName);
    dehttpize(g.urlPath);
    g.urlCanonical = mprintf("http://%T:%d%T", g.urlName, g.urlPort, g.urlPath);


  }else if( strncmp(zUrl, "file:", 5)==0 ){
    g.urlIsFile = 1;
    if( zUrl[5]=='/' && zUrl[6]=='/' ){
      i = 7;
    }else{
      i = 5;
    }








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








>
>
>
>
>
>
>
>
>
>






<
<
<
<
<
<
<
<
<
|
<
<
<
>
>

<

<
>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125









126



127
128
129

130

131
132
133
134
135
136
137
138
139
**
*******************************************************************************
**
** This file contains code for parsing URLs that appear on the command-line
*/
#include "config.h"
#include "url.h"

/* Parse a URI authority. The parsed syntax is:
**
**     [<username> : <password> @] <hostname> [: <port>]
**
** TODO: If the input string does not match this pattern, results are
** undefined (but should not crash or anything nasty like that).
*/
void url_parse_authority(char const *zUri, int *pIdx){
  char *zUser = 0;
  char *zPass = 0;
  char *zHost = 0;
  int iPort = 80;

  int iFirst = *pIdx;
  int iColon = -1;
  int ii;

  /* Scan for the magic "@". If the authority contains this character,
  ** then we need to parse a username and password.
  */
  for(ii=iFirst; zUri[ii] && zUri[ii]!='@' && zUri[ii]!= '/'; ii++){
    if( zUri[ii]==':' ) iColon = ii;
  }

  /* Parse the username and (optional) password. */
  if( zUri[ii]=='@' ){
    if( iColon>=0 ){
      zUser = mprintf("%.*s", iColon-iFirst, &zUri[iFirst]);
      zPass = mprintf("%.*s", ii-(iColon+1), &zUri[iColon+1]);
    }else{
      zUser = mprintf("%.*s", ii-iFirst, &zUri[iFirst]);
    }
    iFirst = ii+1;
  }

  /* Parse the hostname. */
  for(ii=iFirst; zUri[ii] && zUri[ii]!=':' && zUri[ii]!= '/'; ii++);
  zHost = mprintf("%.*s", ii-iFirst, &zUri[iFirst]);

  /* Parse the port number, if one is specified. */
  if( zUri[ii]==':' ){
    iPort = atoi(&zUri[ii+1]);
    for(ii=iFirst; zUri[ii] && zUri[ii]!= '/'; ii++);
  }

  /* Set the g.urlXXX variables to the parsed values. */
  dehttpize(zUser);
  dehttpize(zPass);
  dehttpize(zHost);
  g.urlUsername = zUser;
  g.urlPassword = zPass;
  g.urlName = zHost;
  g.urlPort = iPort;

  *pIdx = ii;
}

/*
** Based on the values already stored in the other g.urlXXX variables,
** set the g.urlCanonical variable.
*/
void url_set_canon(){
  g.urlCanonical = mprintf("http://%T%s%T%s%T:%d%T", 
    (g.urlUsername ? g.urlUsername : ""),
    (g.urlPassword ? ":" : ""),
    (g.urlPassword ? g.urlPassword : ""),
    (g.urlUsername ? "@" : ""),
    g.urlName, g.urlPort, g.urlPath
  );
  /* printf("%s\n", g.urlCanonical); */
}

/*
** Parse the given URL.  Populate variables in the global "g" structure.
**
**      g.urlIsFile      True if this is a file URL
**      g.urlName        Hostname for HTTP:.  Filename for FILE:
**      g.urlPort        Port name for HTTP.
**      g.urlPath        Path name for HTTP.
**      g.urlCanonical   The URL in canonical form
**
** If g.uriIsFile is false, indicating an http URI, then the following
** variables are also populated:
**
**      g.urlUsername
**      g.urlPassword
**
** TODO: At present, the only way to specify a username is to pass it
** as part of the URI. In the future, if no password is specified, 
** fossil should use the get_passphrase() routine (user.c) to obtain
** a password from the user.
*/
void url_parse(const char *zUrl){
  int i, j, c;
  char *zFile;
  if( strncmp(zUrl, "http:", 5)==0 ){
    g.urlIsFile = 0;













    i = 7;
    url_parse_authority(zUrl, &i);
    g.urlPath = mprintf(&zUrl[i]);

    dehttpize(g.urlPath);

    url_set_canon();

  }else if( strncmp(zUrl, "file:", 5)==0 ){
    g.urlIsFile = 1;
    if( zUrl[5]=='/' && zUrl[6]=='/' ){
      i = 7;
    }else{
      i = 5;
    }