Writing "8011" into CLIENTDIR/webport causes the client to run a webserver on port 8011. Writing "tcp:8011:interface=127.0.0.1" into CLIENTDIR/webport does the same but binds to the loopback interface, ensuring that only the programs on the local host can connect. Using "ssl:8011:privateKey=mykey.pem:certKey=cert.pem" would run an SSL server. See twisted.application.strports for more details. If CLIENTDIR/webpassword exists, it will be used (somehow) to require HTTP Digest Authentication for all webserver connections. The client provides some small number of "virtual drives". In the 0.4.0 release, this number is two: the first is the global shared vdrive, the second is the private non-shared vdrive. We will call these "global" and "private" for now. For the purpose of this document, let us assume that the vdrives currently contain the following directories and files: global/ global/Documents/ global/Documents/notes.txt private/ private/Pictures/ private/Pictures/tractors.jpg == vdrive == Within the webserver, there is a tree of resources. The top-level "vdrive" resource gives access to files and directories in all of the user's virtual drives. For example, the URL that corresponds to notes.txt would be: FILEURL = http://localhost:8011/vdrive/global/Documents/notes.txt and the URL for tractors.jpg would be: http://localhost:8011/vdrive/private/Pictures/tractors.jpg In addition, each directory has a corresponding URL. The Pictures URL is: DIRURL = http://localhost:8011/vdrive/private/Pictures Now, what can we do with these URLs? By varying the HTTP "method" (GET/PUT/POST/DELETE) and by appending a type-indicating query argument, we control how what we want to do with the data and how it should be presented. In the following examples, FILEURL and DIRURL are abbreviations for the previously listed examples. In addition. NEWFILEURL and NEWDIRURL are URLs for files and directories which do not yet exist. === Files === GET FILEURL This simply retrives the contents of the file at the given place in the vdrive. The Content-Type is set according to the vdrive's metadata (if available) or by using the usual filename-extension-magic built into most webservers. The file's contents are provided in the body of the HTTP response. (thought: we could conceivably provide some measure of gathering-peers progress and pre-plaintext status information by emitting some extra X-Tahoe-Status headers. Of course, once the headers are done and we start sending plaintext, we have to stop sending such headers) PUT NEWFILEURL This uploads a file to the given place in the vdrive. It will create intermediate directory nodes as necessary. The file's contents are taken from the body of the HTTP request. For convenience, the HTTP response contains the URI that results from uploading the file, although the client is not obligated to do anything with the URI. According to the HTTP/1.1 specification (rfc2616), this should return a 200 (OK) code when modifying an existing file, and a 201 (Created) code when creating a new file. To use this, run 'curl -T localfile http://localhost:8011/vdrive/global/newfile' DELETE FILEURL This deletes the given file from the vdrive. Note that this *does not* delete any parent directories, so a sequence of 'PUT NEWFILEURL' and 'DELETE NEWFILEURL' does not necessarily return the vdrive to its original state (it may leave some intermediate directory nodes). GET FILEURL?t=json This returns machine-parseable information about the file in the HTTP response body, including file size, metadata (like Content-Type), and URIs. This information is also required to contain a flag that distinguishes between files and directories. Programatic clients are expected to use this query before actually downloading the file's contents. The JSON data is as follows: [ 'filenode', { 'mutable': bool, 'uri': file_uri, 'size': bytes } ] GET FILEURL?t=download&localfile=$FILENAME This instructs the client to download the given file and write its contents into the local filesystem at $FILENAME. This request will only be accepted from an HTTP client connection originating at 127.0.0.1 . This request is most useful when the client node and the HTTP client are operated by the same user. $FILENAME should be an absolute pathname. (thoughts: we could use either the response headers or the response body to indicate download progress) PUT NEWFILEURL?t=upload&localfile=$FILENAME This uploads file to the vdrive and gets the contents from a file in the client's local filesystem. As with GET, this request will only be accepted from an HTTP connection originating from 127.0.0.1. (we could indicate upload progress too. The response body could contain the URI of the uploaded file) GET FILEURL?t=uri This returns the URI of the given file in the HTTP response body. GET FILEURL?t=readonly-uri This also returns the URI of the given file. For now, all files are immutable, so t=uri and t=readonly-uri return the same value. In the future, when we have mutable files, they will return different values. === Directories === GET DIRURL This returns an HTML page, intended to be used by humans, which contains HREF links to all files and directories reachable from this dirnode. These HREF links do not have a t= argument, meaning that a human who follows them will get pages also meant for a human. It also contains forms to upload new files, and to delete files and directories. These forms use POST methods to do their job. GET DIRURL?t=json This returns machine-parseable information about this directory in the HTTP response body. This information first contains a flag to indicate that DIRURL referenced a directory (as opposed to a file). Then it contains a flag to indicate whether this is a read-write dirnode or a read-only dirnode. Finally it also contains information about the children of this directory, probably as a mapping from child name to a set of metadata about the child (basically the same data that would appear in a corresponding GET?t=json of the child itself). A programmatic client should be able to use the information from this query to display filesystem navigation choices to a human user. The JSON data is as follows: [ 'dirnode', { 'mutable': bool, 'uri': uri, 'children': children } ] where 'children' is a dictionary in which the keys are child names and the values depend upon whether the child is a file or a directory: 'foo.txt': [ 'filenode', { 'mutable': bool, 'uri': uri, 'size': bytes } ] 'subdir': [ 'dirnode', { 'mutable': bool, 'uri': uri } ] note that the value is the same as the JSON representation of the corresponding FILEURL or DIRURL (except that dirnodes do not recurse). GET DIRURL?t=uri GET DIRURL?t=readonly-uri Return a URI for this dirnode in the HTTP response body. If the dirnode is read-only, the t=uri and t=readonly-uri responses will be the same. GET DIRURL?t=manifest Return an HTML-formatted manifest of the given directory, for debugging. PUT NEWDIRURL?t=mkdir Create a new empty directory at the given path. The HTTP response contains the URI of the given directory, although the client is not obligated to do anything with it. DELETE DIRURL This deletes the given directory (and all of its children). Note that this *does not* delete any parent directories, so a sequence of 'PUT NEWDIRURL?t=mkdir' and 'DELETE NEWDIRURL does not necessarily return the vdrive to its original state (it may leave some intermediate directory nodes). GET DIRURL?t=download&localdir=$DIRNAME This instructs the client to perform a recursive download of the given directory and all its descendant files and directories, writing the results to the local filesystem starting at DIRNAME. (thoughts: we could use the response headers or the response body to indicate download progress) PUT NEWDIRURL?t=upload&localdir=$DIRNAME This instructs the client to perform a recursive upload of a directory on the local filesystem into the vdrive at the given location. NEWDIRURL will be created if necessary. When the operation is complete, the directory referenced by NEWDIRURL will contain all of the files and directories that were present in DIRNAME, so this is equivalent to the unix commands: mkdir -p NEWDIRURL; cp -r DIRNAME/* NEWDIRURL/ Note that the "curl" utility can be used to provoke this sort of recursive upload, since the -T option will make it use an HTTP 'PUT': curl -T /dev/null 'http://localhost:8011/vdrive/global/newdir?t=upload&localdir=/home/user/directory-to-upload' GET DIRURL?t=rename-form&name=$CHILDNAME This provides a useful facility to browser-based user interfaces. It returns a page containing a form targetting the POST DIRURL t=rename functionality listed below, with the provided $CHILDNAME present in the 'from_name' field of that form. i.e. this presents a form offering to rename $CHILDNAME, requesting the new name, and submitting POST rename == POST Forms == POST DIRURL t=upload name=childname (optional) file=newfile This instructs the client to upload a file into the given dirnode. We need this because forms are the only way for a web browser to upload a file (browsers do not know how to do PUT or DELETE). The file's contents and the new child name will be included in the form's arguments. This can only be used to upload a single file at a time. To avoid confusion, name= is not allowed to contain a slash (a 400 Bad Request error will result). POST DIRURL t=mkdir name=childname This instructs the client to create a new empty directory. The name of the new child directory will be included in the form's arguments. POST DIRURL t=uri name=childname uri=newuri This instructs the client to attach a child that is referenced by URI (just like the PUT NEWFILEURL?t=uri method). The name and URI of the new child will be included in the form's arguments. POST DIRURL t=delete name=childname This instructs the client to delete a file from the given dirnode. The name of the child to be deleted will be included in the form's arguments. POST DIRURL t=rename from_name=oldchildname to_name=newchildname This instructs the client to rename a child within the given dirnode. The child specified by 'from_name' is removed, and reattached as a child named for 'to_name'. This is unconditional and will replace any child already present under 'to_name', akin to 'mv -f' in unix parlance. == URI == http://localhost:8011/uri/$URI A separate top-level resource namespace ("uri" instead of "vdrive") is used to get access to files and dirnodes that are indexed directly by URI, rather than by going through the vdrive. The resource thus referenced is used the same way as if it were accessed through the vdrive, including child-resource-traversal behavior. For example, if the URI corresponds to a file, then GET http://localhost:8011/uri/$URI would retrieve the contents of the file. Since files accessed this way do not have a naturally-occurring filename (from which a MIME-type can be derived), one can be specified using a 'filename=' query argument. This filename is also the one used if the 'save=true' argument is set, which adds a 'Content-Disposition: attachment' header to prompt most web browsers to save the file to disk rather than attempting to display it: GET http://localhost:8011/uri/$URI?filename=foo.jpg GET http://localhost:8011/uri/$URI?filename=foo.jpg&save=true If the URI corresponds to a directory, then: PUT http://localhost:8011/uri/$URI/subdir/newfile?localfile=$FILENAME would upload a file (with contents taken from the local filesystem) to a new file in a subdirectory of the referenced dirnode. Note that since tahoe URIs may contain slashes (in particular, dirnode URIs contain a FURL, which resembles a regular HTTP URL and starts with pb://), when URIs are used in this form, they must be specially quoted. All slashes in the URI must be replaced by '!' characters. PUT NEWFILEURL?t=uri This attaches a child (either a file or a directory) to the vdrive at the given location. The URI is provided in the body of the HTTP request. This can be used to attach a shared directory to the vdrive. Intermediate directories are created on-demand just like with the regular PUT command. GET http://localhost:8011/uri?uri=$URI This causes a redirect to /uri/$URI, and retains any additional query arguments (like filename= or save=). This is for the convenience of web forms which allow the user to paste in a URI (obtained through some out-of-band channel, like IM or email). Note that this form only redirects to the specific node indicated by the URI: unlike the GET /uri/$URI form, you cannot traverse to child nodes by appending additional path segments to the URL. The $URI provided as a query argument is allowed to contain slashes. The redirection provided will escape the slashes with exclamation points, as described above. == XMLRPC == http://localhost:8011/xmlrpc This resource provides an XMLRPC server on which all of the previous operations can be expressed as function calls taking a "pathname" argument. This is provided for applications that want to think of everything in terms of XMLRPC. listdir(vdrivename, path) -> dict of (childname -> (stuff)) put(vdrivename, path, contents) -> URI get(vdrivename, path) -> contents mkdir(vdrivename, path) -> URI put_localfile(vdrivename, path, localfilename) -> URI get_localfile(vdrivename, path, localfilename) put_localdir(vdrivename, path, localdirname) # recursive get_localdir(vdrivename, path, localdirname) # recursive put_uri(vdrivename, path, URI) etc..