new webfs, rc based hget
This commit is contained in:
parent
62fb4f9717
commit
75e1ef0ab6
24 changed files with 2412 additions and 6198 deletions
69
rc/bin/hget
Executable file
69
rc/bin/hget
Executable file
|
@ -0,0 +1,69 @@
|
|||
#!/bin/rc
|
||||
argv0=$0
|
||||
fn usage {
|
||||
echo usage: $argv0 [ -o file ] [ -p body ] [ -r header ] [ -m method ] [ -b baseurl ] url >[2=1]
|
||||
exit usage
|
||||
}
|
||||
s=0
|
||||
o=()
|
||||
p=()
|
||||
r=()
|
||||
m=()
|
||||
b=()
|
||||
while(~ $1 -*){
|
||||
switch($1){
|
||||
case -o
|
||||
o=$2
|
||||
shift
|
||||
case -p
|
||||
p=$2
|
||||
shift
|
||||
case -r
|
||||
r=($r $2)
|
||||
shift
|
||||
case -m
|
||||
m=$2
|
||||
shift
|
||||
case -b
|
||||
b=$2
|
||||
shift
|
||||
case *
|
||||
usage
|
||||
}
|
||||
shift
|
||||
}
|
||||
if(! ~ $#* 1)
|
||||
usage
|
||||
if(! ~ $#o 0){
|
||||
if(! ~ $#o 1)
|
||||
usage
|
||||
if(test -s $o)
|
||||
s=`{ls -l $o | awk '{print $6}'}
|
||||
}
|
||||
if(! ~ $s 0)
|
||||
r=($r 'Range: bytes='^$s^'-')
|
||||
<>/mnt/web/clone {
|
||||
d=/mnt/web/^`{sed 1q}
|
||||
if(~ $#b 1)
|
||||
echo -n baseurl $b >[1=0]
|
||||
echo -n url $1 >[1=0]
|
||||
for(i in $r)
|
||||
echo -n headers $i >[1=0]
|
||||
if(~ $#m 1)
|
||||
echo -n request $m >[1=0]
|
||||
if(~ $#p 1)
|
||||
cat <$p >$d/postbody
|
||||
<$d/body {
|
||||
if(~ $#o 1){
|
||||
l=`{cat $d/contentlength >[2]/dev/null}
|
||||
x=`{awk 'BEGIN{FS=" |-"}/^bytes ([0-9]+)\-/{print $2}' \
|
||||
$d/contentrange >[2]/dev/null}
|
||||
if(~ $s $l && ~ $#x 0)
|
||||
exit
|
||||
if(~ $s $x)
|
||||
exec cat >>$o
|
||||
exec cat >$o
|
||||
}
|
||||
exec cat
|
||||
}
|
||||
}
|
10
sys/lib/dist/usr/glenda/lib/profile
vendored
10
sys/lib/dist/usr/glenda/lib/profile
vendored
|
@ -9,9 +9,15 @@ font = /lib/font/bit/pelm/euro.9.font
|
|||
fn cd { builtin cd $* && awd } # for acme
|
||||
switch($service){
|
||||
case terminal
|
||||
if(! test -w $home/lib/webcookies){
|
||||
touch /tmp/webcookies
|
||||
webcookies -f /tmp/webcookies
|
||||
}
|
||||
if not {
|
||||
webcookies
|
||||
}
|
||||
webfs
|
||||
plumber
|
||||
touch /tmp/webcookies
|
||||
webfs -c /tmp/webcookies
|
||||
echo -n accelerated > '#m/mousectl'
|
||||
echo -n 'res 3' > '#m/mousectl'
|
||||
prompt=('term% ' ' ')
|
||||
|
|
|
@ -10,10 +10,11 @@ cd $home
|
|||
x='$'
|
||||
mkdir bin bin/rc bin/mips bin/386 bin/power bin/arm
|
||||
mkdir lib tmp
|
||||
touch lib/webcookies
|
||||
chmod 600 lib/webcookies
|
||||
chmod +t tmp
|
||||
bind -qc /n/other/usr/$user/tmp $home/tmp
|
||||
bind -c $home/tmp /tmp
|
||||
|
||||
mail -c
|
||||
auth/cron -c
|
||||
|
||||
|
@ -26,6 +27,8 @@ bind -c $x^home/tmp /tmp
|
|||
font = /lib/font/bit/pelm/euro.9.font
|
||||
switch($x^service){
|
||||
case terminal
|
||||
webcookies
|
||||
webfs
|
||||
plumber
|
||||
startupasfs
|
||||
echo -n accelerated > '#m/mousectl'
|
||||
|
|
|
@ -4,19 +4,20 @@ hget \- retrieve a web page corresponding to a url
|
|||
.SH SYNOPSIS
|
||||
.B hget
|
||||
[
|
||||
.B -dhv
|
||||
] [
|
||||
.B -o
|
||||
.I ofile
|
||||
.I file
|
||||
] [
|
||||
.B -p
|
||||
.I body
|
||||
] [
|
||||
.B -x
|
||||
.I netmntpt
|
||||
] [
|
||||
.B -r
|
||||
.I header
|
||||
] [
|
||||
.B -m
|
||||
.I method
|
||||
] [
|
||||
.B -b
|
||||
.I baseurl
|
||||
]
|
||||
.I url
|
||||
.SH DESCRIPTION
|
||||
|
@ -26,7 +27,16 @@ retrieves the web page specified by the URL
|
|||
and writes it, absent the
|
||||
.B -o
|
||||
option, to standard output.
|
||||
The known URL types are: http and ftp.
|
||||
.PP
|
||||
The
|
||||
.I url
|
||||
can be a relative path like
|
||||
.B ../index.html
|
||||
if a absolute
|
||||
.I baseurl
|
||||
was specified with the
|
||||
.B -b
|
||||
option.
|
||||
.PP
|
||||
If
|
||||
.I url
|
||||
|
@ -47,40 +57,22 @@ but incomplete,
|
|||
will fetch the missing bytes.
|
||||
.PP
|
||||
Option
|
||||
.B -h
|
||||
causes HTTP headers to be printed to standard output
|
||||
in addition to the transferred web page.
|
||||
.PP
|
||||
Option
|
||||
.B -r
|
||||
sends an arbitrary HTTP
|
||||
.IR header .
|
||||
.PP
|
||||
Option
|
||||
.B -d
|
||||
turns on debugging written to standard error.
|
||||
.PP
|
||||
Normally,
|
||||
.I hget
|
||||
uses the IP stack mounted under
|
||||
.BR /net .
|
||||
The
|
||||
.B -x
|
||||
option can be used to specify the mount point of
|
||||
a different IP stack to use.
|
||||
.PP
|
||||
Option
|
||||
.B -v
|
||||
writes progress lines to standard error once a second.
|
||||
Each line contains two numbers, the bytes transferred so
|
||||
far and the total length to be transferred.
|
||||
.PP
|
||||
If the environment variable
|
||||
.B httpproxy
|
||||
is set, it is used as a URL denoting an HTTP proxy server.
|
||||
All HTTP accesses use this server to get the page instead of
|
||||
calling the destination server.
|
||||
.B -m
|
||||
overrides the HTTP method used for the request.
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/hget.c
|
||||
.B /rc/bin/hget
|
||||
.SH "SEE ALSO"
|
||||
.IR webfs (4),
|
||||
.IR ftpfs (4)
|
||||
.SH DIAGNOSTICS
|
||||
.I Hget
|
||||
requires
|
||||
.IR webfs (4)
|
||||
service mounted on
|
||||
.B /mnt/web
|
||||
to work.
|
||||
|
|
|
@ -147,20 +147,8 @@ If
|
|||
.B cookiefs
|
||||
decides not to accept the cookie (as outlined in
|
||||
RFC2109, section 4.3.4), no indication is given.
|
||||
.PP
|
||||
.IR Hget (1)
|
||||
uses
|
||||
.BR /mnt/webcookies/http ,
|
||||
when it exists, to manage cookie state.
|
||||
.I Webfs
|
||||
does not (yet).
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/webcookies.c
|
||||
.SH SEE ALSO
|
||||
.IR webfs (4),
|
||||
.IR hget (1)
|
||||
.SH BUGS
|
||||
It's not clear what the relationship between
|
||||
.I cookiefs
|
||||
and something like
|
||||
.I webfs
|
||||
should be.
|
||||
|
|
318
sys/man/4/webfs
318
sys/man/4/webfs
|
@ -4,10 +4,6 @@ webfs \- world wide web file system
|
|||
.SH SYNOPSIS
|
||||
.B webfs
|
||||
[
|
||||
.B -c
|
||||
.I cookiefile
|
||||
]
|
||||
[
|
||||
.B -m
|
||||
.I mtpt
|
||||
]
|
||||
|
@ -26,10 +22,15 @@ mounts itself at
|
|||
.BR /mnt/web ),
|
||||
and, if
|
||||
.I service
|
||||
is specified, will post a service file descriptor
|
||||
in
|
||||
is specified, will post a service file descriptor in
|
||||
.BR /srv/\fIservice .
|
||||
.PP
|
||||
If the enviroment variable
|
||||
.B httpproxy
|
||||
is set, all HTTP request initiated by
|
||||
.I webfs
|
||||
will be made thru that proxy url.
|
||||
.PP
|
||||
.I Webfs
|
||||
presents a three-level file system suggestive
|
||||
of the network protocol hierarchies
|
||||
|
@ -37,13 +38,12 @@ of the network protocol hierarchies
|
|||
and
|
||||
.IR ether (3).
|
||||
.PP
|
||||
The top level contains three files:
|
||||
The top level contains the files files:
|
||||
.BR ctl ,
|
||||
.BR cookies ,
|
||||
and
|
||||
.BR clone .
|
||||
.PP
|
||||
The
|
||||
The top level
|
||||
.B ctl
|
||||
file is used to maintain parameters global to the instance of
|
||||
.IR webfs .
|
||||
|
@ -53,72 +53,6 @@ file yields the current values of the parameters.
|
|||
Writing strings of the form
|
||||
.RB `` attr " " value ''
|
||||
sets a particular attribute.
|
||||
Attributes are:
|
||||
.TP
|
||||
.B chatty9p
|
||||
The
|
||||
.B chatty9p
|
||||
flag used by the 9P library, discussed in
|
||||
.IR 9p (2).
|
||||
.B 0
|
||||
is no debugging,
|
||||
.B 1
|
||||
prints 9P message traces on standard error,
|
||||
and values above
|
||||
.B 1
|
||||
present more debugging, at the whim of the library.
|
||||
The default for this and the following debug flags is
|
||||
.BR 0 .
|
||||
.TP
|
||||
.B fsdebug
|
||||
This variable is the level of debugging output about the file system module.
|
||||
.TP
|
||||
.B cookiedebug
|
||||
This variable is the level of debugging output about the cookie module.
|
||||
.TP
|
||||
.B urldebug
|
||||
This variable is the level of debugging output about URL parsing.
|
||||
.TP
|
||||
.B acceptcookies
|
||||
This flag controls whether to accept cookies presented by remote web servers.
|
||||
(Cookies are described below, in the discussion of the
|
||||
.B cookies
|
||||
file.)
|
||||
The values
|
||||
.B on
|
||||
and
|
||||
.B off
|
||||
are synonymous with
|
||||
.B 1
|
||||
and
|
||||
.BR 0 .
|
||||
The default is
|
||||
.BR on .
|
||||
.TP
|
||||
.B sendcookies
|
||||
This flag controls whether to present stored cookies to remote web servers.
|
||||
The default is
|
||||
.BR on .
|
||||
.TP
|
||||
.B redirectlimit
|
||||
Web servers can respond to a request with a message
|
||||
redirecting to another page.
|
||||
.I Webfs
|
||||
makes no effort to determine whether it is in an infinite
|
||||
redirect loop.
|
||||
Instead, it gives up after this many redirects.
|
||||
The default is
|
||||
.BR 10 .
|
||||
.TP
|
||||
.B useragent
|
||||
.I Webfs
|
||||
sends the value of this attribute in its
|
||||
.B User-Agent:
|
||||
header in its HTTP requests.
|
||||
The default is
|
||||
.RB `` "webfs/2.0 (plan 9)" .''
|
||||
.PD
|
||||
.PP
|
||||
The top-level directory also contains
|
||||
numbered directories corresponding to connections, which
|
||||
may be used to fetch a single URL.
|
||||
|
@ -131,23 +65,10 @@ After opening, the
|
|||
.B clone
|
||||
file is equivalent to the file
|
||||
.IB n /ctl \fR.
|
||||
A connection is assumed closed once all files in its directory
|
||||
have been closed, and is then will be reallocated.
|
||||
A connection is assumed closed once all files in its
|
||||
directory have been closed, and is then will be reallocated.
|
||||
.PP
|
||||
Each connection has its own private set of
|
||||
.BR acceptcookies ,
|
||||
.BR sendcookies ,
|
||||
.BR redirectlimit ,
|
||||
and
|
||||
.B useragent
|
||||
variables, initialized to the defaults set in the
|
||||
root's
|
||||
.B ctl
|
||||
file. The per-connection
|
||||
.B ctl
|
||||
file allows editing the variables for this particular connection.
|
||||
.PP
|
||||
Each connection also has a URL string variable
|
||||
Each connection has a URL attribute
|
||||
.B url
|
||||
associated with it.
|
||||
This URL may be an absolute URL such as
|
||||
|
@ -156,153 +77,96 @@ or a relative URL such as
|
|||
.IR ../index.html .
|
||||
The
|
||||
.B baseurl
|
||||
string variable sets the URL against which relative URLs
|
||||
attribute sets the URL against which relative URLs
|
||||
are interpreted.
|
||||
Once the URL has been set,
|
||||
its pieces can be retrieved via individual files in the
|
||||
Once the URL has been set by wrting to the
|
||||
.B ctl
|
||||
file of the connetcion, its pieces can be retrieved via
|
||||
individual files in the
|
||||
.B parsed
|
||||
directory.
|
||||
.I Webfs
|
||||
parses the following URL syntaxes; names in italics are
|
||||
the names of files in the
|
||||
.B parsed
|
||||
directory.
|
||||
.IP
|
||||
\fIscheme\f5:\fIschemedata
|
||||
.br
|
||||
\f5http://\fIhost\f5/\fIpath\fR[\f5?\fIquery\fR][\f5#\fIfragment\fR]
|
||||
.br
|
||||
\f5ftp://\fR[\fIuser\fR[\f5:\fIpassword\fR]\f5@\fR]\fP\f5\fIhost\f5/\fIpath\fR[\f5;type=\fIftptype\fR]
|
||||
.br
|
||||
\f5file:\fIpath
|
||||
.LP
|
||||
If there is associated data to be
|
||||
posted with the request, it can be written to
|
||||
directory:
|
||||
.de UU
|
||||
.TP
|
||||
.B parsed/\fI\\$1
|
||||
\\$2
|
||||
..
|
||||
.UU url http://pete:secret@www.example.com:8000/cgi/search?q=kittens#results
|
||||
.UU scheme http
|
||||
.UU user pete
|
||||
.UU pass secret
|
||||
.UU host www.example.com
|
||||
.UU port 8000
|
||||
.UU path /cgi/search
|
||||
.UU query q=kittens
|
||||
.UU fragment results
|
||||
.PP
|
||||
If there is associated data to be posted with the request,
|
||||
it can be written to
|
||||
.BR postbody .
|
||||
Finally, opening
|
||||
Opening
|
||||
.B postbody
|
||||
or
|
||||
.B body
|
||||
initiates the request.
|
||||
initiates the request. If the request fails,
|
||||
then opening the
|
||||
.B body
|
||||
or writing to
|
||||
.B postbody
|
||||
file will fail and return a error string.
|
||||
.PP
|
||||
When the
|
||||
.B body
|
||||
file has been opend, response headers appear
|
||||
as files in the connection directory. For example
|
||||
reading the
|
||||
.B contenttype
|
||||
file yields the MIME content type of the body data.
|
||||
If the request was redirected, the URL represended
|
||||
by the
|
||||
.B parsed
|
||||
directory will change to the final destination.
|
||||
.PP
|
||||
The resulting data may be read from
|
||||
.B body
|
||||
as it arrives.
|
||||
After the request has been executed, the MIME content type
|
||||
may be read from the
|
||||
.PP
|
||||
The following is a list of attributes that can be
|
||||
set to to a connection prior initiating the request:
|
||||
.TP
|
||||
.B url,baseurl
|
||||
See above.
|
||||
.TP
|
||||
.B useragent
|
||||
Sets a custom useragent string to be used with the request.
|
||||
.TP
|
||||
.B contenttype
|
||||
file.
|
||||
.PP
|
||||
The top-level
|
||||
.B cookies
|
||||
file contains the internal set of HTTP cookies, which
|
||||
are used by HTTP servers to associate requests with persistent
|
||||
state such as user profiles.
|
||||
It may be edited as an ordinary text file.
|
||||
Multiple instances of
|
||||
.I webfs
|
||||
and
|
||||
.IR webcookies (4)
|
||||
share cookies by keeping their internal set
|
||||
consistent with the
|
||||
.I cookiefile
|
||||
(default
|
||||
.BR $home/lib/webcookies ),
|
||||
which has the same format.
|
||||
.PP
|
||||
These files contain one line per cookie;
|
||||
each cookie comprises some number of
|
||||
.IB attr = value
|
||||
pairs.
|
||||
Cookie attributes are:
|
||||
Sets the MIME content type of the postbody.
|
||||
.TP
|
||||
.BI name= name
|
||||
The name of the cookie on the remote server.
|
||||
.B request
|
||||
Usualy, the HTTP method used is
|
||||
.B POST
|
||||
when
|
||||
.B postbody
|
||||
file is opend first or
|
||||
.B GET
|
||||
otherwise. This can be overriden with the
|
||||
.B request
|
||||
attribute so send arbitrary HTTP requests.
|
||||
.TP
|
||||
.BI value= value
|
||||
The value associated with that name on the remote server.
|
||||
The actual data included when a cookie is sent back
|
||||
to the server is
|
||||
.IB \fR``\fIname = value\fR''
|
||||
(where, confusingly,
|
||||
.I name
|
||||
and
|
||||
.I value
|
||||
are the values associated with the
|
||||
.B name
|
||||
and
|
||||
.B value
|
||||
attributes.
|
||||
.TP
|
||||
.BI domain= domain
|
||||
If
|
||||
.I domain
|
||||
is an IP address, the cookie can only be used for URLs
|
||||
with
|
||||
.I host
|
||||
equal to that IP address.
|
||||
Otherwise,
|
||||
.I domain
|
||||
must be a pattern beginning with a dot, and
|
||||
the cookie can only be used for URLs with a
|
||||
.I host
|
||||
having
|
||||
.I domain
|
||||
as a suffix.
|
||||
For example, a cookie with
|
||||
.B domain=.bell-labs.com
|
||||
may be used on hosts
|
||||
.I www.bell-labs.com
|
||||
and
|
||||
.IR www.research.bell-labs.com
|
||||
(but not
|
||||
.IR www.not-bell-labs.com ).
|
||||
.TP
|
||||
.BI path= path
|
||||
The cookie can only be used for URLs with a path
|
||||
beginning with
|
||||
.IR path .
|
||||
.TP
|
||||
.BI version= version
|
||||
The version of the HTTP cookie specification, specified by the server.
|
||||
.TP
|
||||
.BI comment= comment
|
||||
A comment, specified by the server.
|
||||
.TP
|
||||
.BI expire= expire
|
||||
The cookie expires at time
|
||||
.IR expire ,
|
||||
which is a decimal number of seconds since the epoch.
|
||||
.TP
|
||||
.B secure=1
|
||||
The cookie may only be used over secure
|
||||
.RB ( https )
|
||||
connections.
|
||||
Secure connections are currently unimplemented.
|
||||
.TP
|
||||
.B explicitdomain=1
|
||||
The domain associated with this cookie was set by
|
||||
the server (rather than inferred from a URL).
|
||||
.TP
|
||||
.B explicitpath=1
|
||||
The path associated with this cookie was set by the
|
||||
server (rather than inferred from a URL).
|
||||
.TP
|
||||
.B netscapestyle=1
|
||||
The server presented the cookie in ``Netscape style,'' which
|
||||
does not conform to the cookie standard, RFC2109.
|
||||
It is assumed that when presenting the cookie to the server,
|
||||
it must be sent back in Netscape style as well.
|
||||
.PD
|
||||
.B headers
|
||||
Adds arbitrary HTTP headers to be send with
|
||||
the request.
|
||||
.SH EXAMPLE
|
||||
.B /sys/src/cmd/webfs/webget.c
|
||||
.B /rc/bin/hget
|
||||
is a simple client.
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/webfs
|
||||
.SH SEE ALSO
|
||||
.IR hget (1),
|
||||
.IR webcookies (4)
|
||||
.SH BUGS
|
||||
It's not clear what the relationship between
|
||||
.IR hget ,
|
||||
.I webcookies
|
||||
and
|
||||
.I webfs
|
||||
should be.
|
||||
.SH "SEE ALSO"
|
||||
.IR webcookies (4),
|
||||
.IR hget (1)
|
||||
.SH DIAGNOSTICS
|
||||
For cookies to work,
|
||||
.IR webcookies (4),
|
||||
should be running and mounted on
|
||||
.B /mnt/webcookies
|
||||
otherwise cookies will be ignored.
|
||||
|
|
1480
sys/src/cmd/hget.c
1480
sys/src/cmd/hget.c
File diff suppressed because it is too large
Load diff
|
@ -1,89 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <ip.h>
|
||||
#include <plumb.h>
|
||||
#include <thread.h>
|
||||
#include <fcall.h>
|
||||
#include <9p.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
void
|
||||
initibuf(Ibuf *b, Ioproc *io, int fd)
|
||||
{
|
||||
b->fd = fd;
|
||||
b->io = io;
|
||||
b->rp = b->wp = b->buf;
|
||||
}
|
||||
|
||||
int
|
||||
readibuf(Ibuf *b, char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = b->wp - b->rp;
|
||||
if(n > 0){
|
||||
if(n > len)
|
||||
n = len;
|
||||
memmove(buf, b->rp, n);
|
||||
b->rp += n;
|
||||
return n;
|
||||
}
|
||||
return ioreadn(b->io, b->fd, buf, len);
|
||||
}
|
||||
|
||||
void
|
||||
unreadline(Ibuf *b, char *line)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
i = strlen(line);
|
||||
n = b->wp - b->rp;
|
||||
memmove(&b->buf[i+1], b->rp, n);
|
||||
memmove(b->buf, line, i);
|
||||
b->buf[i] = '\n';
|
||||
b->rp = b->buf;
|
||||
b->wp = b->rp+i+1+n;
|
||||
}
|
||||
|
||||
int
|
||||
readline(Ibuf *b, char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
char *p;
|
||||
|
||||
len--;
|
||||
|
||||
for(p = buf;;){
|
||||
if(b->rp >= b->wp){
|
||||
n = ioread(b->io, b->fd, b->wp, sizeof(b->buf)/2);
|
||||
if(n < 0)
|
||||
return -1;
|
||||
if(n == 0)
|
||||
break;
|
||||
b->wp += n;
|
||||
}
|
||||
n = *b->rp++;
|
||||
if(len > 0){
|
||||
*p++ = n;
|
||||
len--;
|
||||
}
|
||||
if(n == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
/* drop trailing white */
|
||||
for(;;){
|
||||
if(p <= buf)
|
||||
break;
|
||||
n = *(p-1);
|
||||
if(n != ' ' && n != '\t' && n != '\r' && n != '\n')
|
||||
break;
|
||||
p--;
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
return p-buf;
|
||||
}
|
||||
|
263
sys/src/cmd/webfs/buq.c
Normal file
263
sys/src/cmd/webfs/buq.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
#include <fcall.h>
|
||||
#include <thread.h>
|
||||
#include <9p.h>
|
||||
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static void
|
||||
matchreq(Buq *q)
|
||||
{
|
||||
Req *r;
|
||||
Buf *b;
|
||||
int l;
|
||||
|
||||
while(r = q->rh){
|
||||
if((b = q->bh) == nil){
|
||||
if(q->closed){
|
||||
if((q->rh = r->aux) == nil)
|
||||
q->rt = &q->rh;
|
||||
if(r->ifcall.type == Tread)
|
||||
r->ofcall.count = 0;
|
||||
respond(r, q->error);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if((q->rh = r->aux) == nil)
|
||||
q->rt = &q->rh;
|
||||
if(r->ifcall.type == Topen){
|
||||
respond(r, nil);
|
||||
continue;
|
||||
}
|
||||
l = b->ep - b->rp;
|
||||
if(l > r->ifcall.count)
|
||||
l = r->ifcall.count;
|
||||
memmove(r->ofcall.data, b->rp, l);
|
||||
r->ofcall.count = l;
|
||||
respond(r, nil);
|
||||
b->rp += l;
|
||||
q->size -= l;
|
||||
if(b->rp >= b->ep){
|
||||
if((q->bh = b->next) == nil)
|
||||
q->bt = &q->bh;
|
||||
if(r = b->wreq){
|
||||
r->ofcall.count = r->ifcall.count;
|
||||
respond(r, nil);
|
||||
}
|
||||
free(b);
|
||||
}
|
||||
}
|
||||
rwakeupall(&q->rz);
|
||||
}
|
||||
|
||||
int
|
||||
buread(Buq *q, void *v, int l)
|
||||
{
|
||||
Req *r;
|
||||
Buf *b;
|
||||
|
||||
qlock(q);
|
||||
while((b = q->bh) == nil){
|
||||
if(q->closed){
|
||||
l = 0;
|
||||
if(q->error){
|
||||
werrstr("%s", q->error);
|
||||
l = -1;
|
||||
}
|
||||
qunlock(q);
|
||||
return l;
|
||||
}
|
||||
rsleep(&q->rz);
|
||||
}
|
||||
if(l > (b->ep - b->rp))
|
||||
l = b->ep - b->rp;
|
||||
memmove(v, b->rp, l);
|
||||
b->rp += l;
|
||||
q->size -= l;
|
||||
rwakeup(&q->rz);
|
||||
if(b->rp < b->ep){
|
||||
qunlock(q);
|
||||
return l;
|
||||
}
|
||||
if((q->bh = b->next) == nil)
|
||||
q->bt = &q->bh;
|
||||
qunlock(q);
|
||||
if(r = b->wreq){
|
||||
r->ofcall.count = r->ifcall.count;
|
||||
respond(r, nil);
|
||||
}
|
||||
free(b);
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
buwrite(Buq *q, void *v, int l)
|
||||
{
|
||||
Buf *b;
|
||||
|
||||
b = emalloc(sizeof(*b) + l);
|
||||
b->wreq = nil;
|
||||
b->rp = b->end;
|
||||
b->ep = b->rp + l;
|
||||
memmove(b->rp, v, l);
|
||||
b->next = nil;
|
||||
qlock(q);
|
||||
if(q->closed){
|
||||
l = 0;
|
||||
if(q->error){
|
||||
werrstr("%s", q->error);
|
||||
l = -1;
|
||||
}
|
||||
qunlock(q);
|
||||
free(b);
|
||||
return l;
|
||||
}
|
||||
*q->bt = b;
|
||||
q->bt = &b->next;
|
||||
q->size += l;
|
||||
matchreq(q);
|
||||
while(!q->closed && q->size >= q->limit)
|
||||
rsleep(&q->rz);
|
||||
qunlock(q);
|
||||
return l;
|
||||
}
|
||||
|
||||
void
|
||||
buclose(Buq *q, char *error)
|
||||
{
|
||||
if(q == nil)
|
||||
return;
|
||||
qlock(q);
|
||||
if(!q->closed){
|
||||
if(error)
|
||||
q->error = estrdup9p(error);
|
||||
q->closed = 1;
|
||||
matchreq(q);
|
||||
}
|
||||
qunlock(q);
|
||||
}
|
||||
|
||||
Buq*
|
||||
bualloc(int limit)
|
||||
{
|
||||
Buq *q;
|
||||
|
||||
q = emalloc(sizeof(*q));
|
||||
q->limit = limit;
|
||||
q->rt = &q->rh;
|
||||
q->bt = &q->bh;
|
||||
q->rz.l = q;
|
||||
incref(q);
|
||||
return q;
|
||||
}
|
||||
|
||||
void
|
||||
bufree(Buq *q)
|
||||
{
|
||||
Buf *b;
|
||||
Key *k;
|
||||
|
||||
if(q == nil || decref(q))
|
||||
return;
|
||||
while(b = q->bh){
|
||||
q->bh = b->next;
|
||||
free(b);
|
||||
}
|
||||
freeurl(q->url);
|
||||
while(k = q->hdr){
|
||||
q->hdr = k->next;
|
||||
free(k);
|
||||
}
|
||||
free(q->error);
|
||||
free(q);
|
||||
}
|
||||
|
||||
void
|
||||
bureq(Buq *q, Req *r)
|
||||
{
|
||||
Buf *b;
|
||||
int l;
|
||||
|
||||
switch(r->ifcall.type){
|
||||
default:
|
||||
respond(r, "bug in bureq");
|
||||
return;
|
||||
case Twrite:
|
||||
l = r->ifcall.count;
|
||||
if((q->size + l) < q->limit){
|
||||
r->ofcall.count = buwrite(q, r->ifcall.data, r->ifcall.count);
|
||||
respond(r, nil);
|
||||
return;
|
||||
}
|
||||
b = emalloc(sizeof(*b));
|
||||
b->wreq = r;
|
||||
b->rp = (uchar*)r->ifcall.data;
|
||||
b->ep = b->rp + l;
|
||||
b->next = nil;
|
||||
qlock(q);
|
||||
*q->bt = b;
|
||||
q->bt = &b->next;
|
||||
q->size += l;
|
||||
break;
|
||||
case Tread:
|
||||
case Topen:
|
||||
r->aux = nil;
|
||||
qlock(q);
|
||||
*q->rt = r;
|
||||
q->rt = (Req**)&r->aux;
|
||||
break;
|
||||
}
|
||||
matchreq(q);
|
||||
qunlock(q);
|
||||
}
|
||||
|
||||
void
|
||||
buflushreq(Buq *q, Req *r)
|
||||
{
|
||||
Buf **bb, *b;
|
||||
Req **rr;
|
||||
int l;
|
||||
|
||||
switch(r->ifcall.type){
|
||||
default:
|
||||
respond(r, "bug in bufflushreq");
|
||||
return;
|
||||
case Twrite:
|
||||
qlock(q);
|
||||
for(bb = &q->bh; b = *bb; bb = &b->next){
|
||||
if(b->wreq != r)
|
||||
continue;
|
||||
/* fake successfull write */
|
||||
l = b->ep - b->rp;
|
||||
b = realloc(b, sizeof(*b) + l);
|
||||
memmove(b->end, b->rp, l);
|
||||
b->rp = b->end;
|
||||
b->ep = b->rp + l;
|
||||
b->wreq = nil;
|
||||
*bb = b;
|
||||
if(b->next == nil)
|
||||
q->bt = &b->next;
|
||||
r->ofcall.count = r->ifcall.count;
|
||||
respond(r, nil);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Topen:
|
||||
case Tread:
|
||||
qlock(q);
|
||||
for(rr = &q->rh; *rr; rr = (Req**)&((*rr)->aux)){
|
||||
if(*rr != r)
|
||||
continue;
|
||||
if((*rr = r->aux) == nil)
|
||||
q->rt = rr;
|
||||
respond(r, "interrupted");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
qunlock(q);
|
||||
}
|
|
@ -1,411 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <ip.h>
|
||||
#include <plumb.h>
|
||||
#include <thread.h>
|
||||
#include <fcall.h>
|
||||
#include <9p.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
int nclient;
|
||||
Client **client;
|
||||
|
||||
static void clientthread(void*);
|
||||
int
|
||||
newclient(int plumbed)
|
||||
{
|
||||
int i;
|
||||
Client *c;
|
||||
|
||||
for(i=0; i<nclient; i++)
|
||||
if(client[i]->ref==0)
|
||||
return i;
|
||||
|
||||
c = emalloc(sizeof(Client));
|
||||
c->plumbed = plumbed;
|
||||
c->creq = chancreate(sizeof(Req*), 8);
|
||||
threadcreate(clientthread, c, STACK);
|
||||
|
||||
c->io = ioproc();
|
||||
c->num = nclient;
|
||||
c->ctl = globalctl;
|
||||
clonectl(&c->ctl);
|
||||
if(nclient%16 == 0)
|
||||
client = erealloc(client, (nclient+16)*sizeof(client[0]));
|
||||
client[nclient++] = c;
|
||||
return nclient-1;
|
||||
}
|
||||
|
||||
void
|
||||
closeclient(Client *c)
|
||||
{
|
||||
if(--c->ref == 0){
|
||||
if(c->bodyopened){
|
||||
if(c->url && c->url->close)
|
||||
(*c->url->close)(c);
|
||||
c->bodyopened = 0;
|
||||
}
|
||||
free(c->contenttype);
|
||||
c->contenttype = nil;
|
||||
free(c->postbody);
|
||||
c->postbody = nil;
|
||||
freeurl(c->url);
|
||||
c->url = nil;
|
||||
freeurl(c->baseurl);
|
||||
c->baseurl = nil;
|
||||
free(c->redirect);
|
||||
c->redirect = nil;
|
||||
free(c->authenticate);
|
||||
c->authenticate = nil;
|
||||
c->npostbody = 0;
|
||||
c->havepostbody = 0;
|
||||
c->bodyopened = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clonectl(Ctl *c)
|
||||
{
|
||||
if(c->useragent)
|
||||
c->useragent = estrdup(c->useragent);
|
||||
}
|
||||
|
||||
void
|
||||
clientbodyopen(Client *c, Req *r)
|
||||
{
|
||||
char e[ERRMAX], *next, *frag;
|
||||
int i, nauth;
|
||||
Url *u;
|
||||
|
||||
nauth = 0;
|
||||
next = nil;
|
||||
for(i=0; i<=c->ctl.redirectlimit; i++){
|
||||
if(c->url == nil){
|
||||
werrstr("nil url");
|
||||
goto Error;
|
||||
}
|
||||
if(c->url->open == nil){
|
||||
werrstr("unsupported url type");
|
||||
goto Error;
|
||||
}
|
||||
if(fsdebug)
|
||||
fprint(2, "try %s\n", c->url->url);
|
||||
if(c->url->open(c, c->url) < 0){
|
||||
Error:
|
||||
rerrstr(e, sizeof e);
|
||||
if(next)
|
||||
fprint(2, "next %s (but for error)\n", next);
|
||||
free(next);
|
||||
c->iobusy = 0;
|
||||
if(r != nil)
|
||||
r->fid->omode = -1;
|
||||
closeclient(c); /* not opening */
|
||||
if(r != nil)
|
||||
respond(r, e);
|
||||
return;
|
||||
}
|
||||
free(next);
|
||||
next = c->redirect;
|
||||
c->redirect = nil;
|
||||
if(c->authenticate && nauth++ < 1){
|
||||
if(c->url->close)
|
||||
(*c->url->close)(c);
|
||||
continue;
|
||||
}
|
||||
if(next == nil)
|
||||
break;
|
||||
if(i==c->ctl.redirectlimit){
|
||||
werrstr("redirect limit reached");
|
||||
goto Error;
|
||||
}
|
||||
if((u = parseurl(next, c->url)) == nil)
|
||||
goto Error;
|
||||
/* if there was a redirect, carry over the fragment */
|
||||
if((frag = c->url->fragment) && u->fragment == nil){
|
||||
u->fragment = estrdup(frag);
|
||||
rewriteurl(u);
|
||||
}
|
||||
if(urldebug)
|
||||
fprint(2, "parseurl %s got scheme %d\n", next, u->ischeme);
|
||||
if(u->ischeme == USunknown){
|
||||
werrstr("redirect with unknown URL scheme");
|
||||
goto Error;
|
||||
}
|
||||
if(u->ischeme == UScurrent){
|
||||
werrstr("redirect to URL relative to current document");
|
||||
goto Error;
|
||||
}
|
||||
if(c->url->close)
|
||||
(*c->url->close)(c);
|
||||
freeurl(c->url);
|
||||
c->url = u;
|
||||
}
|
||||
free(next);
|
||||
c->iobusy = 0;
|
||||
if(r != nil)
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
void
|
||||
plumburl(char *url, char *base)
|
||||
{
|
||||
int i;
|
||||
Client *c;
|
||||
Url *ubase, *uurl;
|
||||
|
||||
ubase = nil;
|
||||
if(base){
|
||||
ubase = parseurl(base, nil);
|
||||
if(ubase == nil)
|
||||
return;
|
||||
}
|
||||
uurl = parseurl(url, ubase);
|
||||
if(uurl == nil){
|
||||
freeurl(ubase);
|
||||
return;
|
||||
}
|
||||
i = newclient(1);
|
||||
c = client[i];
|
||||
c->ref++;
|
||||
c->baseurl = ubase;
|
||||
c->url = uurl;
|
||||
sendp(c->creq, nil);
|
||||
}
|
||||
|
||||
void
|
||||
clientbodyread(Client *c, Req *r)
|
||||
{
|
||||
char e[ERRMAX];
|
||||
|
||||
if(c->url->read == nil){
|
||||
respond(r, "unsupported url type");
|
||||
return;
|
||||
}
|
||||
if(c->url->read(c, r) < 0){
|
||||
rerrstr(e, sizeof e);
|
||||
c->iobusy = 0;
|
||||
respond(r, e);
|
||||
return;
|
||||
}
|
||||
c->iobusy = 0;
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
clientthread(void *a)
|
||||
{
|
||||
Client *c;
|
||||
Req *r;
|
||||
|
||||
c = a;
|
||||
if(c->plumbed) {
|
||||
recvp(c->creq);
|
||||
if(c->url == nil){
|
||||
fprint(2, "bad url got plumbed\n");
|
||||
return;
|
||||
}
|
||||
clientbodyopen(c, nil);
|
||||
replumb(c);
|
||||
}
|
||||
while((r = recvp(c->creq)) != nil){
|
||||
if(fsdebug)
|
||||
fprint(2, "clientthread %F\n", &r->ifcall);
|
||||
switch(r->ifcall.type){
|
||||
case Topen:
|
||||
if(c->plumbed) {
|
||||
c->plumbed = 0;
|
||||
c->ref--; /* from plumburl() */
|
||||
respond(r, nil);
|
||||
}
|
||||
else
|
||||
clientbodyopen(c, r);
|
||||
break;
|
||||
case Tread:
|
||||
clientbodyread(c, r);
|
||||
break;
|
||||
case Tflush:
|
||||
respond(r, nil);
|
||||
}
|
||||
if(fsdebug)
|
||||
fprint(2, "clientthread finished req\n");
|
||||
}
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
Bool,
|
||||
Int,
|
||||
String,
|
||||
XRel,
|
||||
XUrl,
|
||||
Fn,
|
||||
};
|
||||
|
||||
typedef struct Ctab Ctab;
|
||||
struct Ctab {
|
||||
char *name;
|
||||
int type;
|
||||
void *offset;
|
||||
};
|
||||
|
||||
Ctab ctltab[] = {
|
||||
"acceptcookies", Bool, (void*)offsetof(Ctl, acceptcookies),
|
||||
"sendcookies", Bool, (void*)offsetof(Ctl, sendcookies),
|
||||
"redirectlimit", Int, (void*)offsetof(Ctl, redirectlimit),
|
||||
"useragent", String, (void*)offsetof(Ctl, useragent),
|
||||
};
|
||||
|
||||
Ctab globaltab[] = {
|
||||
"chatty9p", Int, &chatty9p,
|
||||
"fsdebug", Int, &fsdebug,
|
||||
"cookiedebug", Int, &cookiedebug,
|
||||
"urldebug", Int, &urldebug,
|
||||
"httpdebug", Int, &httpdebug,
|
||||
};
|
||||
|
||||
Ctab clienttab[] = {
|
||||
"baseurl", XUrl, (void*)offsetof(Client, baseurl),
|
||||
"url", XRel, (void*)offsetof(Client, url),
|
||||
};
|
||||
|
||||
static Ctab*
|
||||
findcmd(char *cmd, Ctab *tab, int ntab)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<ntab; i++)
|
||||
if(strcmp(tab[i].name, cmd) == 0)
|
||||
return &tab[i];
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void
|
||||
parseas(Req *r, char *arg, int type, void *a)
|
||||
{
|
||||
Url *u, *base;
|
||||
char e[ERRMAX];
|
||||
|
||||
base = nil;
|
||||
switch(type){
|
||||
case Bool:
|
||||
if(strcmp(arg, "on")==0 || strcmp(arg, "1")==0)
|
||||
*(int*)a = 1;
|
||||
else
|
||||
*(int*)a = 0;
|
||||
break;
|
||||
case String:
|
||||
free(*(char**)a);
|
||||
*(char**)a = estrdup(arg);
|
||||
break;
|
||||
case XRel:
|
||||
base = ((Client*)a)->baseurl;
|
||||
case XUrl:
|
||||
u = parseurl(arg, base);
|
||||
if(u == nil){
|
||||
snprint(e, sizeof e, "parseurl: %r");
|
||||
respond(r, e);
|
||||
return;
|
||||
}
|
||||
freeurl(*(Url**)a);
|
||||
*(Url**)a = u;
|
||||
break;
|
||||
case Int:
|
||||
if(strcmp(arg, "on")==0)
|
||||
*(int*)a = 1;
|
||||
else
|
||||
*(int*)a = atoi(arg);
|
||||
break;
|
||||
}
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
int
|
||||
ctlwrite(Req *r, Ctl *ctl, char *cmd, char *arg)
|
||||
{
|
||||
void *a;
|
||||
Ctab *t;
|
||||
|
||||
if((t = findcmd(cmd, ctltab, nelem(ctltab))) == nil)
|
||||
return 0;
|
||||
a = (void*)((uintptr)ctl+(uintptr)t->offset);
|
||||
parseas(r, arg, t->type, a);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
clientctlwrite(Req *r, Client *c, char *cmd, char *arg)
|
||||
{
|
||||
void *a;
|
||||
Ctab *t;
|
||||
|
||||
if((t = findcmd(cmd, clienttab, nelem(clienttab))) == nil)
|
||||
return 0;
|
||||
a = (void*)((uintptr)c+(uintptr)t->offset);
|
||||
parseas(r, arg, t->type, a);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
globalctlwrite(Req *r, char *cmd, char *arg)
|
||||
{
|
||||
void *a;
|
||||
Ctab *t;
|
||||
|
||||
if((t = findcmd(cmd, globaltab, nelem(globaltab))) == nil)
|
||||
return 0;
|
||||
a = t->offset;
|
||||
parseas(r, arg, t->type, a);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
ctlfmt(Ctl *c, char *s)
|
||||
{
|
||||
int i;
|
||||
void *a;
|
||||
char *t;
|
||||
|
||||
for(i=0; i<nelem(ctltab); i++){
|
||||
a = (void*)((uintptr)c+(uintptr)ctltab[i].offset);
|
||||
switch(ctltab[i].type){
|
||||
case Bool:
|
||||
s += sprint(s, "%s %s\n", ctltab[i].name, *(int*)a ? "on" : "off");
|
||||
break;
|
||||
case Int:
|
||||
s += sprint(s, "%s %d\n", ctltab[i].name, *(int*)a);
|
||||
break;
|
||||
case String:
|
||||
t = *(char**)a;
|
||||
if(t != nil)
|
||||
s += sprint(s, "%s %.*s%s\n", ctltab[i].name, utfnlen(t, 100), t, strlen(t)>100 ? "..." : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ctlread(Req *r, Client *c)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
sprint(buf, "%11d \n", c->num);
|
||||
ctlfmt(&c->ctl, buf+strlen(buf));
|
||||
readstr(r, buf);
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
void
|
||||
globalctlread(Req *r)
|
||||
{
|
||||
char buf[1024], *s;
|
||||
int i;
|
||||
|
||||
s = buf;
|
||||
for(i=0; i<nelem(globaltab); i++)
|
||||
s += sprint(s, "%s %d\n", globaltab[i].name, *(int*)globaltab[i].offset);
|
||||
ctlfmt(&globalctl, s);
|
||||
readstr(r, buf);
|
||||
respond(r, nil);
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,104 +1,67 @@
|
|||
typedef struct Client Client;
|
||||
typedef struct Ctl Ctl;
|
||||
typedef struct Ibuf Ibuf;
|
||||
typedef struct Url Url;
|
||||
typedef struct Buq Buq;
|
||||
typedef struct Buf Buf;
|
||||
typedef struct Key Key;
|
||||
|
||||
/* simple buffered i/o for network connections; shared by http, ftp */
|
||||
struct Ibuf
|
||||
{
|
||||
int fd;
|
||||
Ioproc *io;
|
||||
char buf[4096];
|
||||
char *rp, *wp;
|
||||
};
|
||||
typedef struct {
|
||||
char *s1;
|
||||
char *s2;
|
||||
} Str2;
|
||||
|
||||
struct Ctl
|
||||
{
|
||||
int acceptcookies;
|
||||
int sendcookies;
|
||||
int redirectlimit;
|
||||
char *useragent;
|
||||
};
|
||||
|
||||
struct Client
|
||||
{
|
||||
Url *url;
|
||||
Url *baseurl;
|
||||
|
||||
Ctl ctl;
|
||||
Channel *creq; /* chan(Req*) */
|
||||
int num;
|
||||
int plumbed;
|
||||
char *contenttype;
|
||||
char *postbody;
|
||||
char *redirect;
|
||||
char *authenticate;
|
||||
char *ext;
|
||||
int npostbody;
|
||||
int havepostbody;
|
||||
int iobusy;
|
||||
int bodyopened;
|
||||
Ioproc *io;
|
||||
int ref;
|
||||
void *aux;
|
||||
};
|
||||
|
||||
/*
|
||||
* If ischeme is USunknown, then the given URL is a relative
|
||||
* URL which references the "current document" in the context of the base.
|
||||
* If this is the case, only the "fragment" and "url" members will have
|
||||
* meaning, and the given URL structure may not be used as a base URL itself.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
USunknown,
|
||||
UShttp,
|
||||
UShttps,
|
||||
USftp,
|
||||
USfile,
|
||||
UScurrent,
|
||||
};
|
||||
/* 9p */
|
||||
typedef struct Req Req;
|
||||
|
||||
struct Url
|
||||
{
|
||||
int ischeme;
|
||||
char* url;
|
||||
char* scheme;
|
||||
int (*open)(Client*, Url*);
|
||||
int (*read)(Client*, Req*);
|
||||
void (*close)(Client*);
|
||||
char* schemedata;
|
||||
char* authority;
|
||||
char* user;
|
||||
char* passwd;
|
||||
char* host;
|
||||
char* port;
|
||||
char* path;
|
||||
char* query;
|
||||
char* fragment;
|
||||
union {
|
||||
struct {
|
||||
char *page_spec;
|
||||
} http;
|
||||
struct {
|
||||
char *path_spec;
|
||||
char *type;
|
||||
} ftp;
|
||||
};
|
||||
char *scheme;
|
||||
char *user;
|
||||
char *pass;
|
||||
char *host;
|
||||
char *port;
|
||||
char *path;
|
||||
char *query;
|
||||
char *fragment;
|
||||
};
|
||||
|
||||
enum
|
||||
struct Buf
|
||||
{
|
||||
STACK = 32*1024, /* was 16*1024; there are big arrays on the stack */
|
||||
Buf *next;
|
||||
uchar *rp;
|
||||
uchar *ep;
|
||||
Req *wreq;
|
||||
uchar end[];
|
||||
};
|
||||
|
||||
extern Client** client;
|
||||
extern int cookiedebug;
|
||||
extern Srv fs;
|
||||
extern int fsdebug;
|
||||
extern Ctl globalctl;
|
||||
extern int nclient;
|
||||
extern int urldebug;
|
||||
extern int httpdebug;
|
||||
extern char* status[];
|
||||
struct Key
|
||||
{
|
||||
Key *next;
|
||||
char *val;
|
||||
char key[];
|
||||
};
|
||||
|
||||
struct Buq
|
||||
{
|
||||
Ref;
|
||||
QLock;
|
||||
|
||||
Url *url;
|
||||
Key *hdr;
|
||||
char *error;
|
||||
|
||||
int closed;
|
||||
int limit;
|
||||
int size;
|
||||
|
||||
/* write buffers */
|
||||
Buf *bh;
|
||||
Buf **bt;
|
||||
|
||||
/* read requests */
|
||||
Req *rh;
|
||||
Req **rt;
|
||||
|
||||
Rendez rz;
|
||||
};
|
||||
|
||||
int debug;
|
||||
Url *proxy;
|
||||
|
|
|
@ -1,62 +1,35 @@
|
|||
/* buf.c */
|
||||
void initibuf(Ibuf*, Ioproc*, int);
|
||||
int readibuf(Ibuf*, char*, int);
|
||||
void unreadline(Ibuf*, char*);
|
||||
int readline(Ibuf*, char*, int);
|
||||
/* sub */
|
||||
void* emalloc(int n);
|
||||
char* estrdup(char *s);
|
||||
|
||||
/* client.c */
|
||||
int newclient(int);
|
||||
void closeclient(Client*);
|
||||
void clonectl(Ctl*);
|
||||
int ctlwrite(Req*, Ctl*, char*, char*);
|
||||
int clientctlwrite(Req*, Client*, char*, char*);
|
||||
int globalctlwrite(Req*, char*, char*);
|
||||
void ctlread(Req*, Client*);
|
||||
void globalctlread(Req*);
|
||||
void plumburl(char*, char*);
|
||||
Key* addkey(Key *h, char *key, char *val);
|
||||
Key* delkey(Key *h, char *key);
|
||||
char* lookkey(Key *k, char *key);
|
||||
Key* parsehdr(char *s);
|
||||
char* unquote(char *s, char **ps);
|
||||
|
||||
/* cookies.c */
|
||||
void cookieread(Req*);
|
||||
void cookiewrite(Req*);
|
||||
void cookieopen(Req*);
|
||||
void cookieclunk(Fid*);
|
||||
void initcookies(char*);
|
||||
void closecookies(void);
|
||||
void httpsetcookie(char*, char*, char*);
|
||||
char* httpcookies(char*, char*, int);
|
||||
/* url */
|
||||
#pragma varargck type "U" Url*
|
||||
#pragma varargck type "E" Str2
|
||||
|
||||
/* fs.c */
|
||||
void initfs(void);
|
||||
int Efmt(Fmt*);
|
||||
int Ufmt(Fmt*);
|
||||
char* Upath(Url *);
|
||||
Url* url(char *s, Url *b);
|
||||
Url* saneurl(Url *u);
|
||||
int matchurl(Url *u, Url *s);
|
||||
void freeurl(Url *u);
|
||||
|
||||
/* http.c */
|
||||
int httpopen(Client*, Url*);
|
||||
int httpread(Client*, Req*);
|
||||
void httpclose(Client*);
|
||||
/* buq */
|
||||
int buread(Buq *q, void *v, int l);
|
||||
int buwrite(Buq *q, void *v, int l);
|
||||
void buclose(Buq *q, char *error);
|
||||
Buq* bualloc(int limit);
|
||||
void bufree(Buq *q);
|
||||
|
||||
/* io.c */
|
||||
int iotlsdial(Ioproc*, char*, char*, char*, int*, int);
|
||||
int ioprint(Ioproc*, int, char*, ...);
|
||||
#pragma varargck argpos ioprint 3
|
||||
void bureq(Buq *q, Req *r);
|
||||
void buflushreq(Buq *q, Req *r);
|
||||
|
||||
/* plumb.c */
|
||||
void plumbinit(void);
|
||||
void plumbstart(void);
|
||||
void replumb(Client*);
|
||||
|
||||
/* url.c */
|
||||
Url* parseurl(char*, Url*);
|
||||
void freeurl(Url*);
|
||||
void rewriteurl(Url*);
|
||||
int seturlquery(Url*, char*);
|
||||
Url* copyurl(Url*);
|
||||
char* escapeurl(char*, char *);
|
||||
char* unescapeurl(char*, char *);
|
||||
void initurl(void);
|
||||
|
||||
/* util.c */
|
||||
char* estrdup(char*);
|
||||
char* estrmanydup(char*, ...);
|
||||
char* estredup(char*, char*);
|
||||
void* emalloc(uint);
|
||||
void* erealloc(void*, uint);
|
||||
char* strlower(char*);
|
||||
/* http */
|
||||
void flushauth(Url *u, char *t);
|
||||
void http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost);
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,86 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <ip.h>
|
||||
#include <plumb.h>
|
||||
#include <thread.h>
|
||||
#include <fcall.h>
|
||||
#include <9p.h>
|
||||
#include <mp.h>
|
||||
#include <libsec.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static long
|
||||
_iovfprint(va_list *arg)
|
||||
{
|
||||
int fd;
|
||||
char *fmt;
|
||||
va_list arg2;
|
||||
|
||||
fd = va_arg(*arg, int);
|
||||
fmt = va_arg(*arg, char*);
|
||||
arg2 = va_arg(*arg, va_list);
|
||||
return vfprint(fd, fmt, arg2);
|
||||
}
|
||||
|
||||
int
|
||||
iovfprint(Ioproc *io, int fd, char *fmt, va_list arg)
|
||||
{
|
||||
return iocall(io, _iovfprint, fd, fmt, arg);
|
||||
}
|
||||
|
||||
int
|
||||
ioprint(Ioproc *io, int fd, char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
n = iovfprint(io, fd, fmt, arg);
|
||||
va_end(arg);
|
||||
return n;
|
||||
}
|
||||
|
||||
static long
|
||||
_iotlsdial(va_list *arg)
|
||||
{
|
||||
char *addr, *local, *dir;
|
||||
int *cfdp, fd, tfd, usetls;
|
||||
TLSconn conn;
|
||||
|
||||
addr = va_arg(*arg, char*);
|
||||
local = va_arg(*arg, char*);
|
||||
dir = va_arg(*arg, char*);
|
||||
cfdp = va_arg(*arg, int*);
|
||||
usetls = va_arg(*arg, int);
|
||||
|
||||
fd = dial(addr, local, dir, cfdp);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
if(!usetls)
|
||||
return fd;
|
||||
|
||||
memset(&conn, 0, sizeof conn);
|
||||
/* does no good, so far anyway */
|
||||
// conn.chain = readcertchain("/sys/lib/ssl/vsignss.pem");
|
||||
|
||||
tfd = tlsClient(fd, &conn);
|
||||
close(fd);
|
||||
if(tfd < 0)
|
||||
fprint(2, "%s: tlsClient: %r\n", argv0);
|
||||
else {
|
||||
/* BUG: check cert here? */
|
||||
if(conn.cert)
|
||||
free(conn.cert);
|
||||
if(conn.sessionID)
|
||||
free(conn.sessionID);
|
||||
}
|
||||
return tfd;
|
||||
}
|
||||
|
||||
int
|
||||
iotlsdial(Ioproc *io, char *addr, char *local, char *dir, int *cfdp, int usetls)
|
||||
{
|
||||
return iocall(io, _iotlsdial, addr, local, dir, cfdp, usetls);
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <ip.h>
|
||||
#include <plumb.h>
|
||||
#include <thread.h>
|
||||
#include <fcall.h>
|
||||
#include <9p.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
char *cookiefile;
|
||||
char *mtpt = "/mnt/web";
|
||||
char *service;
|
||||
|
||||
Ctl globalctl =
|
||||
{
|
||||
1, /* accept cookies */
|
||||
1, /* send cookies */
|
||||
10, /* redirect limit */
|
||||
"webfs/2.0 (plan 9)" /* user agent */
|
||||
};
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: webfs [-c cookies] [-m mtpt] [-s service]\n");
|
||||
threadexitsall("usage");
|
||||
}
|
||||
|
||||
#include <pool.h>
|
||||
void
|
||||
threadmain(int argc, char **argv)
|
||||
{
|
||||
rfork(RFNOTEG);
|
||||
ARGBEGIN{
|
||||
case 'd':
|
||||
mainmem->flags |= POOL_PARANOIA|POOL_ANTAGONISM;
|
||||
break;
|
||||
case 'D':
|
||||
chatty9p++;
|
||||
break;
|
||||
case 'c':
|
||||
cookiefile = EARGF(usage());
|
||||
break;
|
||||
case 'm':
|
||||
mtpt = EARGF(usage());
|
||||
break;
|
||||
case 's':
|
||||
service = EARGF(usage());
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
quotefmtinstall();
|
||||
if(argc != 0)
|
||||
usage();
|
||||
|
||||
plumbinit();
|
||||
globalctl.useragent = estrdup(globalctl.useragent);
|
||||
initcookies(cookiefile);
|
||||
initurl();
|
||||
initfs();
|
||||
threadpostmountsrv(&fs, service, mtpt, MREPL);
|
||||
threadexits(nil);
|
||||
}
|
|
@ -1,35 +1,8 @@
|
|||
</$objtype/mkfile
|
||||
BIN=/$objtype/bin
|
||||
|
||||
TARG=webfs
|
||||
|
||||
SCHEMEOFILES=\
|
||||
file.$O\
|
||||
ftp.$O\
|
||||
http.$O\
|
||||
|
||||
OFILES=\
|
||||
buf.$O\
|
||||
client.$O\
|
||||
cookies.$O\
|
||||
fs.$O\
|
||||
http.$O\
|
||||
io.$O\
|
||||
main.$O\
|
||||
plumb.$O\
|
||||
url.$O\
|
||||
util.$O\
|
||||
# $SCHEMEOFILES
|
||||
|
||||
HFILES=\
|
||||
dat.h\
|
||||
fns.h\
|
||||
|
||||
UPDATE=\
|
||||
mkfile\
|
||||
$HFILES\
|
||||
${OFILES:%.$O=%.c}\
|
||||
${TARG:%=/386/bin/%}\
|
||||
HFILES=fns.h dat.h
|
||||
OFILES=sub.$O url.$O buq.$O http.$O fs.$O
|
||||
|
||||
</sys/src/cmd/mkone
|
||||
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
#include <fcall.h>
|
||||
#include <thread.h>
|
||||
#include <plumb.h>
|
||||
#include <9p.h>
|
||||
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static int plumbsendfd;
|
||||
static int plumbwebfd;
|
||||
static Channel *plumbchan;
|
||||
|
||||
static void plumbwebproc(void*);
|
||||
static void plumbwebthread(void*);
|
||||
static void plumbsendproc(void*);
|
||||
|
||||
void
|
||||
plumbinit(void)
|
||||
{
|
||||
plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
|
||||
plumbwebfd = plumbopen("web", OREAD|OCEXEC);
|
||||
}
|
||||
|
||||
void
|
||||
plumbstart(void)
|
||||
{
|
||||
plumbchan = chancreate(sizeof(Plumbmsg*), 0);
|
||||
proccreate(plumbwebproc, nil, STACK);
|
||||
threadcreate(plumbwebthread, nil, STACK);
|
||||
}
|
||||
|
||||
static void
|
||||
plumbwebthread(void*)
|
||||
{
|
||||
char *base;
|
||||
Plumbmsg *m;
|
||||
|
||||
for(;;){
|
||||
m = recvp(plumbchan);
|
||||
if(m == nil)
|
||||
threadexits(nil);
|
||||
base = plumblookup(m->attr, "baseurl");
|
||||
if(base == nil)
|
||||
base = m->wdir;
|
||||
plumburl(m->data, base);
|
||||
plumbfree(m);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
plumbwebproc(void*)
|
||||
{
|
||||
Plumbmsg *m;
|
||||
|
||||
for(;;){
|
||||
m = plumbrecv(plumbwebfd);
|
||||
sendp(plumbchan, m);
|
||||
if(m == nil)
|
||||
threadexits(nil);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
addattr(Plumbmsg *m, char *name, char *value)
|
||||
{
|
||||
Plumbattr *a;
|
||||
|
||||
a = malloc(sizeof(Plumbattr));
|
||||
a->name = name;
|
||||
a->value = value;
|
||||
a->next = m->attr;
|
||||
m->attr = a;
|
||||
}
|
||||
|
||||
static void
|
||||
freeattrs(Plumbmsg *m)
|
||||
{
|
||||
Plumbattr *a, *next;
|
||||
|
||||
a = m->attr;
|
||||
while(a != nil) {
|
||||
next = a->next;
|
||||
free(a);
|
||||
a = next;
|
||||
}
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
char *ctype;
|
||||
char *ext;
|
||||
}
|
||||
ctypes[] =
|
||||
{
|
||||
{ "application/msword", "doc" },
|
||||
{ "application/pdf", "pdf" },
|
||||
{ "application/postscript", "ps" },
|
||||
{ "application/rtf", "rtf" },
|
||||
{ "image/gif", "gif" },
|
||||
{ "image/jpeg", "jpg" },
|
||||
{ "image/png", "png" },
|
||||
{ "image/ppm", "ppm" },
|
||||
{ "image/tiff", "tiff" },
|
||||
{ "text/html", "html" },
|
||||
{ "text/plain", "txt" },
|
||||
{ "text/xml", "xml" },
|
||||
};
|
||||
|
||||
void
|
||||
replumb(Client *c)
|
||||
{
|
||||
int i;
|
||||
Plumbmsg *m;
|
||||
char name[128], *ctype, *ext, *p;
|
||||
|
||||
if(!c->plumbed)
|
||||
return;
|
||||
m = emalloc(sizeof(Plumbmsg));
|
||||
m->src = "webfs";
|
||||
m->dst = nil;
|
||||
m->wdir = "/";
|
||||
m->type = "text";
|
||||
m->attr = nil;
|
||||
addattr(m, "url", c->url->url);
|
||||
ctype = c->contenttype;
|
||||
ext = nil;
|
||||
if(ctype != nil) {
|
||||
addattr(m, "content-type", ctype);
|
||||
for(i = 0; i < nelem(ctypes); i++) {
|
||||
if(strcmp(ctype, ctypes[i].ctype) == 0) {
|
||||
ext = ctypes[i].ext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ext == nil) {
|
||||
p = strrchr(c->url->url, '/');
|
||||
if(p != nil)
|
||||
p = strrchr(p+1, '.');
|
||||
if(p != nil && strlen(p) <= 5)
|
||||
ext = p+1;
|
||||
else
|
||||
ext = "txt"; /* punt */
|
||||
}
|
||||
c->ext = ext;
|
||||
if(0)fprint(2, "content type %s -> extension .%s\n", ctype, ext);
|
||||
m->ndata = snprint(name, sizeof name, "/mnt/web/%d/body.%s", c->num, ext);
|
||||
m->data = estrdup(name);
|
||||
proccreate(plumbsendproc, m, STACK); /* separate proc to avoid a deadlock */
|
||||
}
|
||||
|
||||
static void
|
||||
plumbsendproc(void *x)
|
||||
{
|
||||
Plumbmsg *m;
|
||||
|
||||
m = x;
|
||||
plumbsend(plumbsendfd, m);
|
||||
freeattrs(m);
|
||||
free(m->data);
|
||||
free(m);
|
||||
}
|
119
sys/src/cmd/webfs/sub.c
Normal file
119
sys/src/cmd/webfs/sub.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
#include <fcall.h>
|
||||
#include <thread.h>
|
||||
#include <9p.h>
|
||||
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
void*
|
||||
emalloc(int n)
|
||||
{
|
||||
void *v;
|
||||
v = emalloc9p(n);
|
||||
setmalloctag(v, getcallerpc(&n));
|
||||
memset(v, 0, n);
|
||||
return v;
|
||||
}
|
||||
|
||||
char*
|
||||
estrdup(char *s)
|
||||
{
|
||||
s = estrdup9p(s);
|
||||
setmalloctag(s, getcallerpc(&s));
|
||||
return s;
|
||||
}
|
||||
|
||||
Key*
|
||||
addkey(Key *h, char *key, char *val)
|
||||
{
|
||||
Key *k;
|
||||
int n;
|
||||
|
||||
if(val == nil)
|
||||
val = "";
|
||||
n = strlen(key)+1;
|
||||
k = emalloc(sizeof(*k) + n + strlen(val)+1);
|
||||
k->next = h;
|
||||
k->val = k->key + n;
|
||||
strcpy(k->key, key);
|
||||
strcpy(k->val, val);
|
||||
return k;
|
||||
}
|
||||
|
||||
Key*
|
||||
delkey(Key *h, char *key)
|
||||
{
|
||||
Key *k, *p;
|
||||
|
||||
for(p = nil, k = h; k; p = k, k = k->next){
|
||||
if(!cistrcmp(k->key, key)){
|
||||
if(p)
|
||||
p->next = k->next;
|
||||
else
|
||||
h = k->next;
|
||||
memset(k->val, 0, strlen(k->val));
|
||||
free(k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
char*
|
||||
lookkey(Key *k, char *key)
|
||||
{
|
||||
while(k){
|
||||
if(!cistrcmp(k->key, key))
|
||||
return k->val;
|
||||
k = k->next;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
Key*
|
||||
parsehdr(char *s)
|
||||
{
|
||||
char *v;
|
||||
|
||||
v = strchr(s, 0)-1;
|
||||
while(v >= s && strchr("\n\r\t ", *v))
|
||||
*v-- = 0;
|
||||
if(v = strchr(s, ':')){
|
||||
*v++ = 0;
|
||||
while(strchr("\t ", *v))
|
||||
v++;
|
||||
if(*s && *v)
|
||||
return addkey(0, s, v);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
unquote(char *s, char **ps)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if(*s != '"'){
|
||||
p = strpbrk(s, " \t\r\n");
|
||||
*p++ = 0;
|
||||
*ps = p;
|
||||
return s;
|
||||
}
|
||||
for(p=s+1; *p; p++){
|
||||
if(*p == '\"'){
|
||||
*p++ = 0;
|
||||
break;
|
||||
}
|
||||
if(*p == '\\' && *(p+1)){
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
memmove(s, s+1, p-(s+1));
|
||||
s[p-(s+1)] = 0;
|
||||
*ps = p;
|
||||
return s;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,86 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <ndb.h>
|
||||
#include <fcall.h>
|
||||
#include <thread.h>
|
||||
#include <9p.h>
|
||||
#include <ctype.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
void*
|
||||
erealloc(void *a, uint n)
|
||||
{
|
||||
a = realloc(a, n);
|
||||
if(a == nil)
|
||||
sysfatal("realloc %d: out of memory", n);
|
||||
setrealloctag(a, getcallerpc(&a));
|
||||
return a;
|
||||
}
|
||||
|
||||
void*
|
||||
emalloc(uint n)
|
||||
{
|
||||
void *a;
|
||||
|
||||
a = mallocz(n, 1);
|
||||
if(a == nil)
|
||||
sysfatal("malloc %d: out of memory", n);
|
||||
setmalloctag(a, getcallerpc(&n));
|
||||
return a;
|
||||
}
|
||||
|
||||
char*
|
||||
estrdup(char *s)
|
||||
{
|
||||
s = strdup(s);
|
||||
if(s == nil)
|
||||
sysfatal("strdup: out of memory");
|
||||
setmalloctag(s, getcallerpc(&s));
|
||||
return s;
|
||||
}
|
||||
|
||||
char*
|
||||
estredup(char *s, char *e)
|
||||
{
|
||||
char *t;
|
||||
|
||||
t = emalloc(e-s+1);
|
||||
memmove(t, s, e-s);
|
||||
t[e-s] = '\0';
|
||||
setmalloctag(t, getcallerpc(&s));
|
||||
return t;
|
||||
}
|
||||
|
||||
char*
|
||||
estrmanydup(char *s, ...)
|
||||
{
|
||||
char *p, *t;
|
||||
int len;
|
||||
va_list arg;
|
||||
|
||||
len = strlen(s);
|
||||
va_start(arg, s);
|
||||
while((p = va_arg(arg, char*)) != nil)
|
||||
len += strlen(p);
|
||||
len++;
|
||||
|
||||
t = emalloc(len);
|
||||
strcpy(t, s);
|
||||
va_start(arg, s);
|
||||
while((p = va_arg(arg, char*)) != nil)
|
||||
strcat(t, p);
|
||||
return t;
|
||||
}
|
||||
|
||||
char*
|
||||
strlower(char *s)
|
||||
{
|
||||
char *t;
|
||||
|
||||
for(t=s; *t; t++)
|
||||
if('A' <= *t && *t <= 'Z')
|
||||
*t += 'a'-'A';
|
||||
return s;
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Sample client.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
xfer(int from, int to)
|
||||
{
|
||||
char buf[12*1024];
|
||||
int n;
|
||||
|
||||
while((n = read(from, buf, sizeof buf)) > 0)
|
||||
if(write(to, buf, n) < 0)
|
||||
sysfatal("write failed: %r");
|
||||
if(n < 0)
|
||||
sysfatal("read failed: %r");
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: webget [-b baseurl] [-m mtpt] [-p postbody] url\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int conn, ctlfd, fd, n;
|
||||
char buf[128], *base, *mtpt, *post, *url;
|
||||
|
||||
mtpt = "/mnt/web";
|
||||
post = nil;
|
||||
base = nil;
|
||||
ARGBEGIN{
|
||||
default:
|
||||
usage();
|
||||
case 'b':
|
||||
base = EARGF(usage());
|
||||
break;
|
||||
case 'm':
|
||||
mtpt = EARGF(usage());
|
||||
break;
|
||||
case 'p':
|
||||
post = EARGF(usage());
|
||||
break;
|
||||
}ARGEND;
|
||||
|
||||
if (argc != 1)
|
||||
usage();
|
||||
|
||||
url = argv[0];
|
||||
|
||||
snprint(buf, sizeof buf, "%s/clone", mtpt);
|
||||
if((ctlfd = open(buf, ORDWR)) < 0)
|
||||
sysfatal("couldn't open %s: %r", buf);
|
||||
if((n = read(ctlfd, buf, sizeof buf-1)) < 0)
|
||||
sysfatal("reading clone: %r");
|
||||
if(n == 0)
|
||||
sysfatal("short read on clone");
|
||||
buf[n] = '\0';
|
||||
conn = atoi(buf);
|
||||
|
||||
if(base)
|
||||
if(fprint(ctlfd, "baseurl %s", base) < 0)
|
||||
sysfatal("baseurl ctl write: %r");
|
||||
|
||||
if(fprint(ctlfd, "url %s", url) <= 0)
|
||||
sysfatal("get ctl write: %r");
|
||||
|
||||
if(post){
|
||||
snprint(buf, sizeof buf, "%s/%d/postbody", mtpt, conn);
|
||||
if((fd = open(buf, OWRITE)) < 0)
|
||||
sysfatal("open %s: %r", buf);
|
||||
if(write(fd, post, strlen(post)) < 0)
|
||||
sysfatal("post write failed: %r");
|
||||
close(fd);
|
||||
}
|
||||
|
||||
snprint(buf, sizeof buf, "%s/%d/body", mtpt, conn);
|
||||
if((fd = open(buf, OREAD)) < 0)
|
||||
sysfatal("open %s: %r", buf);
|
||||
|
||||
xfer(fd, 1);
|
||||
exits(nil);
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/* Example of how to use webfs */
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
xfer(int from, int to)
|
||||
{
|
||||
char buf[12*1024];
|
||||
int n;
|
||||
|
||||
while((n = read(from, buf, sizeof buf)) > 0)
|
||||
if(write(to, buf, n) < 0)
|
||||
sysfatal("write failed: %r");
|
||||
if(n < 0)
|
||||
sysfatal("read failed: %r");
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: webfsget [-b baseurl] [-m mtpt] [-p postbody] url\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int conn, ctlfd, fd, n;
|
||||
char buf[128], *base, *mtpt, *post, *url;
|
||||
|
||||
mtpt = "/mnt/web";
|
||||
post = nil;
|
||||
base = nil;
|
||||
ARGBEGIN{
|
||||
default:
|
||||
usage();
|
||||
case 'b':
|
||||
base = EARGF(usage());
|
||||
break;
|
||||
case 'm':
|
||||
mtpt = EARGF(usage());
|
||||
break;
|
||||
case 'p':
|
||||
post = EARGF(usage());
|
||||
break;
|
||||
}ARGEND;
|
||||
|
||||
if (argc != 1)
|
||||
usage();
|
||||
|
||||
url = argv[0];
|
||||
|
||||
snprint(buf, sizeof buf, "%s/clone", mtpt);
|
||||
if((ctlfd = open(buf, ORDWR)) < 0)
|
||||
sysfatal("couldn't open %s: %r", buf);
|
||||
if((n = read(ctlfd, buf, sizeof buf-1)) < 0)
|
||||
sysfatal("reading clone: %r");
|
||||
if(n == 0)
|
||||
sysfatal("short read on clone");
|
||||
buf[n] = '\0';
|
||||
conn = atoi(buf);
|
||||
|
||||
if(base)
|
||||
if(fprint(ctlfd, "baseurl %s", base) < 0)
|
||||
sysfatal("baseurl ctl write: %r");
|
||||
|
||||
if(fprint(ctlfd, "url %s", url) <= 0)
|
||||
sysfatal("get ctl write: %r");
|
||||
|
||||
if(post){
|
||||
snprint(buf, sizeof buf, "%s/%d/postbody", mtpt, conn);
|
||||
if((fd = open(buf, OWRITE)) < 0)
|
||||
sysfatal("open %s: %r", buf);
|
||||
if(write(fd, post, strlen(post)) < 0)
|
||||
sysfatal("post write failed: %r");
|
||||
close(fd);
|
||||
}
|
||||
|
||||
snprint(buf, sizeof buf, "%s/%d/body", mtpt, conn);
|
||||
if((fd = open(buf, OREAD)) < 0)
|
||||
sysfatal("open %s: %r", buf);
|
||||
|
||||
xfer(fd, 1);
|
||||
exits(nil);
|
||||
}
|
Loading…
Reference in a new issue