Check-in [3dcaed8d86]
Not logged in
Overview

SHA1 Hash:3dcaed8d86cde74f050f862f0fc23cb7ea9cc0f1
Date: 2007-07-28 07:09:25
User: dan
Comment:When accessing a remote repository, if there is a username/password specified as part of the URI, use these to login.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/db.c from [e56e457646] to [fcfc75c8b2].

@@ -762,10 +762,41 @@
   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.

Modified src/encode.c from [af8a8318d1] to [6c31150f72].

@@ -182,10 +182,14 @@
 ** 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] ){

Modified src/http.c from [3b83a20834] to [d56d77ab24].

@@ -152,24 +152,41 @@
 ** 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;
 
-  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);
+
+  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", g.zLogin, &nonce, &sig);
+  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;

Modified src/info.c from [cb6cea5bd7] to [199807a9fd].

@@ -103,13 +103,13 @@
     }
     show_common_info(rid, "uuid:", 1);
   }
 }
 
-#if 0
+#if 1
 /*
-** WEB PAGE: vinfo
+** WEBPAGE: vinfo
 **
 ** Return information about a version.  The version number is contained
 ** in g.zExtra.
 */
 void vinfo_page(void){
@@ -123,14 +123,28 @@
   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, datetime(mtime,'unixepoch'), datetime(ctime,'unixepoch'),"
-    "         uid, size, cksum, branch, comment, type"
-    "  FROM record WHERE rid=%d", rid
+    "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",
@@ -256,11 +270,13 @@
     }
     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.

Modified src/main.c from [e0071db8be] to [93362928df].

@@ -70,10 +70,12 @@
   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 */

Modified src/url.c from [f3bcafe705] to [1a6d7505c6].

@@ -24,42 +24,114 @@
 ** 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;
-    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;
-    }
+
+    i = 7;
+    url_parse_authority(zUrl, &i);
     g.urlPath = mprintf(&zUrl[i]);
-    dehttpize(g.urlName);
     dehttpize(g.urlPath);
-    g.urlCanonical = mprintf("http://%T:%d%T", g.urlName, g.urlPort, g.urlPath);
+    url_set_canon();
+
   }else if( strncmp(zUrl, "file:", 5)==0 ){
     g.urlIsFile = 1;
     if( zUrl[5]=='/' && zUrl[6]=='/' ){
       i = 7;
     }else{