1 This document has six sections:
3 1. the basic API for how to programmatically control your tahoe node
5 3. safety and security issues
6 4. features for controlling your tahoe node from a standard web browser
7 5. debugging and testing features
8 6. XML-RPC (coming soon)
11 1. the basic API for how to programmatically control your tahoe node
13 a. connecting to the tahoe node
15 Writing "8123" into $NODEDIR/webport causes the node to run a webserver on
16 port 8123. Writing "tcp:8123:interface=127.0.0.1" into $NODEDIR/webport does
17 the same but binds to the loopback interface, ensuring that only the programs
18 on the local host can connect. Using
19 "ssl:8123:privateKey=mykey.pem:certKey=cert.pem" would run an SSL server. See
20 twisted.application.strports for more details.
22 This webport can be set when the node is created by passing a --webport
23 option to the 'tahoe create-client' command. By default, the node listens on
24 port 8123, on the loopback (127.0.0.1) interface.
28 The node provides some small number of "virtual drives". In the 0.5 release,
29 this number is two: the first is the global shared vdrive, the second is the
30 private non-shared vdrive. We will call the global one "global", and we will
31 refer to the second one by "$PRIVATE_VDRIVE_URI", to show that to use it you
32 have to insert the specific URI for that private vdrive.
34 For the purpose of this document, let us assume that the vdrives currently
35 contain the following directories and files:
39 global/Documents/notes.txt
42 $PRIVATE_VDRIVE_URI/Pictures/
43 $PRIVATE_VDRIVE_URI/Pictures/tractors.jpg
44 $PRIVATE_VDRIVE_URI/Pictures/family/
45 $PRIVATE_VDRIVE_URI/Pictures/family/bobby.jpg
47 Within the webserver, there is a tree of resources. The top-level "vdrive"
48 resource gives access to files and directories in all of the user's virtual
49 drives. For example, the URL that corresponds to notes.txt would be:
51 http://localhost:8123/vdrive/global/Documents/notes.txt
53 and the URL for tractors.jpg would be:
55 http://localhost:8123/uri/$PRIVATE_VDRIVE_URI/Pictures/tractors.jpg
57 In addition, each directory has a corresponding URL. The Pictures URL is:
59 http://localhost:8123/uri/$PRIVATE_VDRIVE_URI/Pictures
63 From the "URIs" chapter in architecture.txt, recall that each file and
64 directory has a unique "URI". This is a string which provides a secure
65 reference to the file or directory: if you know the URI, you can retrieve
66 (and possibly modify) the object. If you don't know the URI, you cannot
69 A separate top-level namespace ("uri/" instead of "vdrive/") is used to
70 access to files and directories directly by URI, rather than by going through
71 the pathnames in the vdrive.
73 For example, this identifies a file or directory:
75 http://localhost:8123/uri/$URI
77 And this identifies a file or directory named "tractors.jpg" in a
78 subdirectory "Pictures" of the identified directory:
80 http://localhost:8123/uri/$URI/Pictures/tractors.jpg
82 In the following examples, "$URL" is a shorthand for a URL like the ones
83 above, either with "vdrive/" and a vdrive name as the top level and a
84 sequence of slash-separated pathnames following, or with "uri/" as the top
85 level, followed by a URI, optionally followed by a sequence of
86 slash-separated pathnames.
89 Now, what can we do with these URLs? By varying the HTTP method
90 (GET/PUT/POST/DELETE) and by appending a type-indicating query argument, we
91 control what we want to do with the data and how it should be presented.
93 d. examining files or directories
99 This returns machine-parseable information about the indicated file or
100 directory in the HTTP response body. The JSON always contains a list, and
101 the first element of the list is always a flag that indicates whether the
102 referenced object is a file or a directory.
104 If it is a file, then the information includes file size and URI, like
107 [ 'filenode', { 'ro_uri': file_uri,
110 If it is a directory, then it includes information about the children of
111 this directory, as a mapping from child name to a set of metadata about the
112 child (the same data that would appear in a corresponding GET?t=json of the
113 child itself). Like this:
115 [ 'dirnode', { 'rw_uri': read_write_uri,
116 'ro_uri': read_only_uri,
117 'children': children } ]
119 In the above example, 'children' is a dictionary in which the keys are
120 child names and the values depend upon whether the child is a file or a
123 'foo.txt': [ 'filenode', { 'ro_uri': uri, 'size': bytes } ]
124 'subdir': [ 'dirnode', { 'rw_uri': rwuri, 'ro_uri': rouri } ]
126 note that the value is the same as the JSON representation of the child
127 object (except that directories do not recurse -- the "children" entry of
128 the child is omitted).
130 Then the rw_uri field will be present in the information about a directory
131 if and only if you have read-write access to that directory,
133 e. downloading a file
137 out: file contents or dir metadata
139 save=<boolean> - If true add header "Content-Disposition: attachment"
141 If the indicated object is a file, then this simply retrieves the contents
142 of the file. The file's contents are provided in the body of the HTTP
145 If the indicated object a directory, then this returns an HTML page,
146 intended to be displayed to a human by a web browser, which contains HREF
147 links to all files and directories reachable from this directory. These
148 HREF links do not have a t= argument, meaning that a human who follows them
149 will get pages also meant for a human. It also contains forms to upload new
150 files, and to delete files and directories. These forms use POST methods to
153 You can add the "save=true" argument, which adds a 'Content-Disposition:
154 attachment' header to prompt most web browsers to save the file to disk
155 rather than attempting to display it.
157 A filename (from which a MIME type can be derived, for use in the
158 Content-Type header) can be specified using a 'filename=' query argument.
159 This is especially useful if the $URL does not end with the name of the
160 file (e.g. if it ends with the URI of the file instead). This filename is
161 also the one used if the 'save=true' argument is set. For example:
163 GET http://localhost:8123/uri/$TRACTORS_URI?filename=tractors.jpg
167 PUT http://localhost:8123/uri
172 Upload a file, using the data from the HTTP request body, and returning
173 the resulting URI as the HTTP response body. This does not make the file
174 visible from the virtual drive -- to do that, see section 1.h. below, or
175 the convenience method in section 2.a..
177 POST http://localhost:8123/uri?t=upload
179 This action also uploads a file without attaching it to a virtual drive
180 directory, but can be used from an HTML form. The response is an HTML page
181 that describes the results of the upload, including the resulting URI (but
182 also including information about which peers were used, etc).
184 POST http://localhost:8123/uri?t=upload&mutable=true
186 This action also uploads a file without attaching it to a virtual drive
187 directory, but creates a mutable file (SSK) instead of an immutable one.
188 The response contains the new URI that was created.
190 PUT http://localhost:8123/uri?mutable=true
192 This second form also accepts data from the HTTP request body, but creates
193 a mutable file (SSK) instead of an immutable one (CHK). The response
194 contains the new URI that was created.
197 g. creating a new directory
199 PUT http://localhost:8123/uri?t=mkdir
202 out: directory write cap
204 Create a new empty directory and return its URI as the HTTP response body.
205 This does not make the newly created directory visible from the virtual
206 drive, but you can use section 1.h. to attach it, or the convenience method
209 h. attaching a file or directory as the child of an extant directory
214 out: the same child cap
216 replace=<boolean> - If true, overwrite existing contents.
218 This attaches a child (either a file or a directory) to the given directory
219 $URL is required to indicate a directory as the second-to-last element and
220 the desired filename as the last element, for example:
222 PUT http://localhost:8123/uri/$URI_OF_SOME_DIR/Pictures/tractors.jpg
223 PUT http://localhost:8123/uri/$URI_OF_SOME_DIR/tractors.jpg
224 PUT http://localhost:8123/uri/$PRIVATE_VDRIVE_URI/Pictures/tractors.jpg
226 (Note that a URI_OF_SOME_DIR and a PRIVATE_VDRIVE_URI are each just
227 separate URIs, and there is nothing special about the latter except that it
228 is useful to put all of the user's top-level files and directories into one
229 place, so we choose to use that particular directory to be the user's main
232 The URI of the child is provided in the body of the HTTP request,
233 and this same URI is returned in the response body.
235 There is an optional "?replace=" param whose value can be "true", "t", "1",
236 "false", "f", or "0" (case-insensitive), and which defaults to "true". If
237 the indicated directory already contains the given child name, then if
238 replace is true then the value of that name is changed to be the new URI.
239 If replace is false then an HTTP 409 "Conflict" error is returned.
241 This can be used to attach a shared directory (a directory that other
242 people can read or write) to the vdrive. Intermediate directories, if any,
243 are created on-demand.
245 i. removing a name from a directory
249 This removes the given name from the given directory. $URL is required to
250 indicate a directory as the second-to-last element and the name to remove
251 from that directory as the last element, just as in section 1.g..
253 Note that this does not actually delete the resource that the name points
254 to from the tahoe grid -- it only removes this name in this directory. If
255 there are other names in this directory or in other directories that point
256 to the resource, then it will remain accessible through those paths. Even
257 if all names pointing to this resource are removed from their parent
258 directories, then if someone is in possession of the URI of this resource
259 they can continue to access the resource through the URI. Only if a person
260 is not in possession of the URI, and they do not have access to any
261 directories which contain names pointing to this resource, are they
262 prevented from accessing the resource. (This behavior is very similar to
263 the way hardlinks and anonymous files work in traditional unix
266 2. convenience methods
268 a. uploading a file and attaching it to the vdrive
276 200 - File updated. [FIXME: Is this true yet?]
277 201 - File created. [FIXME: Is this true yet?]
279 Upload a file and link it into the the vdrive at the location specified by
280 $URI. The last item in the $URI must be a filename, and the second-to-last
281 item must identify a directory.
283 It will create intermediate directories as necessary. The file's contents
284 are taken from the body of the HTTP request. For convenience, the HTTP
285 response contains the URI that results from uploading the file, although
286 the client is not obligated to do anything with the URI. According to the
287 HTTP/1.1 specification (rfc2616), this should return a 200 (OK) code when
288 modifying an existing file, and a 201 (Created) code when creating a new
289 file. (TODO: as of 0.5, the web server only returns 200, never 201).
291 To use this, run 'curl -T localfile http://localhost:8123/vdrive/global/newfile'
293 3. safety and security issues -- names vs. URIs
295 The vdrive provides a mutable filesystem, but the ways that the filesystem
296 can change are limited. The only thing that can change is that the mapping
297 from child names to child objects that each directory contains can be changed
298 by adding a new child name pointing to an object, removing an existing child
299 name, or changing an existing child name to point to a different object.
301 Obviously if you query tahoe for information about the filesystem and then
302 act upon the filesystem (such as by getting a listing of the contents of a
303 directory and then adding a file to the directory), then the filesystem might
304 have been changed after you queried it and before you acted upon it.
305 However, if you use the URI instead of the pathname of an object when you act
306 upon the object, then the only change that can happen is when the object is a
307 directory then the set of child names it has might be different. If, on the
308 other hand, you act upon the object using its pathname, then a different
309 object might be in that place, which can result in more kinds of surprises.
311 For example, suppose you are writing code which recursively downloads the
312 contents of a directory. The first thing your code does is fetch the listing
313 of the contents of the directory. For each child that it fetched, if that
314 child is a file then it downloads the file, and if that child is a directory
315 then it recurses into that directory. Now, if the download and the recurse
316 actions are performed using the child's name, then the results might be
317 wrong, because for example a child name that pointed to a sub-directory when
318 you listed the directory might have been changed to point to a file (in which
319 case your attempt to recurse into it would result in an error and the file
320 would be skipped), or a child name that pointed to a file when you listed the
321 directory might now point to a sub-directory (in which case your attempt to
322 download the child would result in a file containing HTML text describing the
325 If your recursive algorithm uses the uri of the child instead of the name of
326 the child, then those kinds of mistakes just can't happen. Note that both the
327 child's name and the child's URI are included in the results of listing the
328 parent directory, so it isn't any harder to use the URI for this purpose.
330 In general, use names if you want "whatever object (whether file or
331 directory) is found by following this name (or sequence of names) when my
332 request reaches the server". Use URIs if you want "this particular object".
334 4. features for controlling your tahoe node from a standard web browser
338 GET http://localhost:8123/uri?uri=$URI
340 This causes a redirect to /uri/$URI, and retains any additional query
341 arguments (like filename= or save=). This is for the convenience of web
342 forms which allow the user to paste in a URI (obtained through some
343 out-of-band channel, like IM or email).
345 Note that this form merely redirects to the specific file or directory
346 indicated by the URI: unlike the GET /uri/$URI form, you cannot traverse to
347 children by appending additional path segments to the URL.
349 b. web page offering rename
351 GET $URL?t=rename-form&name=$CHILDNAME
353 This provides a useful facility to browser-based user interfaces. It
354 returns a page containing a form targetting the "POST $URL t=rename"
355 functionality described below, with the provided $CHILDNAME present in the
356 'from_name' field of that form. I.e. this presents a form offering to
357 rename $CHILDNAME, requesting the new name, and submitting POST rename.
363 name=childname (optional)
366 This instructs the node to upload a file into the given directory. We need
367 this because forms are the only way for a web browser to upload a file
368 (browsers do not know how to do PUT or DELETE). The file's contents and the
369 new child name will be included in the form's arguments. This can only be
370 used to upload a single file at a time. To avoid confusion, name= is not
371 allowed to contain a slash (a 400 Bad Request error will result). The
372 response is the file read-cap (URI) of the resulting file.
377 name=childname (optional)
381 This instructs the node to upload a file into the given directory, using a
382 mutable file (SSK) rather than the usual immutable file (CHK). As a result,
383 further operations to the same $URL will not cause the identity of the file
384 to change. The response is the file write-cap (URI) of the resulting
392 This is used to replace the existing (mutable) file's contents with new
393 ones. It may only be used when $URL refers to a mutable file, as created by
394 POST $URL?t=upload&mutable=true, or PUT /uri?t=mutable . The name
395 associated with the uploaded file is ignored. TODO: rethink this, it's kind
403 This instructs the node to create a new empty directory. The name of the
404 new child directory will be included in the form's arguments.
412 This instructs the node to attach a child that is referenced by URI (just
413 like the PUT $URL?t=uri method). The name and URI of the new child
414 will be included in the form's arguments.
421 This instructs the node to delete a file from the given directory. The name
422 of the child to be deleted will be included in the form's arguments.
427 from_name=oldchildname
430 This instructs the node to rename a child within the given directory. The
431 child specified by 'from_name' is removed, and reattached as a child named
432 for 'to_name'. This is unconditional and will replace any child already
433 present under 'to_name', akin to 'mv -f' in unix parlance.
439 This triggers the FileChecker to determine the current "health" of the
440 given file, by counting how many shares are available. The results will be
441 displayed on the directory page containing this file.
444 5. debugging and testing features
446 GET $URL?t=download&localfile=$LOCALPATH
447 GET $URL?t=download&localdir=$LOCALPATH
449 The localfile= form instructs the node to download the given file and write
450 it into the local filesystem at $LOCALPATH. The localdir= form instructs
451 the node to recursively download everything from the given directory and
452 below into the local filesystem. To avoid surprises, the localfile= form
453 will signal an error if $URL actually refers to a directory, likewise if
454 localdir= is used with a $URL that refers to a file.
456 This request will only be accepted from an HTTP client connection
457 originating at 127.0.0.1 . This request is most useful when the client node
458 and the HTTP client are operated by the same user. $LOCALPATH should be an
461 This form is only implemented for testing purposes, because of a trivially
462 easy attack: any web server that the local browser visits could serve an
463 IMG tag that causes the local node to modify the local filesystem.
464 Therefore this form is only enabled if you create a file named
465 'webport_allow_localfile' in the node's base directory.
467 PUT $NEWURL?t=upload&localfile=$LOCALPATH
468 PUT $NEWURL?t=upload&localdir=$LOCALPATH
470 This uploads a file or directory from the node's local filesystem to the
471 vdrive. As with "GET $URL?t=download&localfile=$LOCALPATH", this request
472 will only be accepted from an HTTP connection originating from 127.0.0.1 .
474 The localfile= form expects that $LOCALPATH will point to a file on the
475 node's local filesystem, and causes the node to upload that one file into
476 the vdrive at the given location. Any parent directories will be created in
477 the vdrive as necessary.
479 The localdir= form expects that $LOCALPATH will point to a directory on the
480 node's local filesystem, and it causes the node to perform a recursive
481 upload of the directory into the vdrive at the given location, creating
482 parent directories as necessary. When the operation is complete, the
483 directory referenced by $NEWURL will contain all of the files and
484 directories that were present in $LOCALPATH, so this is equivalent to the
487 mkdir -p $NEWURL; cp -r $LOCALPATH/* $NEWURL/
489 Note that the "curl" utility can be used to provoke this sort of recursive
490 upload, since the -T option will make it use an HTTP 'PUT':
492 curl -T /dev/null 'http://localhost:8123/vdrive/global/newdir?t=upload&localdir=/home/user/directory-to-upload'
494 This form is only implemented for testing purposes, because any attacker's
495 web server that a local browser visits could serve an IMG tag that causes
496 the local node to modify the local filesystem. Therefore this form is only
497 enabled if you create a file named 'webport_allow_localfile' in the node's
502 Return an HTML-formatted manifest of the given directory, for debugging.
504 6. XMLRPC (coming soon)
506 http://localhost:8123/xmlrpc
508 This resource provides an XMLRPC server on which all of the previous
509 operations can be expressed as function calls taking a "pathname" argument.
510 This is provided for applications that want to think of everything in terms
513 listdir(vdrivename, path) -> dict of (childname -> (stuff))
514 put(vdrivename, path, contents) -> URI
515 get(vdrivename, path) -> contents
516 mkdir(vdrivename, path) -> URI
517 put_localfile(vdrivename, path, localfilename) -> URI
518 get_localfile(vdrivename, path, localfilename)
519 put_localdir(vdrivename, path, localdirname) # recursive
520 get_localdir(vdrivename, path, localdirname) # recursive
521 put_uri(vdrivename, path, URI)