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
|
fn cd { builtin cd $* && awd } # for acme
|
||||||
switch($service){
|
switch($service){
|
||||||
case terminal
|
case terminal
|
||||||
|
if(! test -w $home/lib/webcookies){
|
||||||
|
touch /tmp/webcookies
|
||||||
|
webcookies -f /tmp/webcookies
|
||||||
|
}
|
||||||
|
if not {
|
||||||
|
webcookies
|
||||||
|
}
|
||||||
|
webfs
|
||||||
plumber
|
plumber
|
||||||
touch /tmp/webcookies
|
|
||||||
webfs -c /tmp/webcookies
|
|
||||||
echo -n accelerated > '#m/mousectl'
|
echo -n accelerated > '#m/mousectl'
|
||||||
echo -n 'res 3' > '#m/mousectl'
|
echo -n 'res 3' > '#m/mousectl'
|
||||||
prompt=('term% ' ' ')
|
prompt=('term% ' ' ')
|
||||||
|
|
|
@ -10,10 +10,11 @@ cd $home
|
||||||
x='$'
|
x='$'
|
||||||
mkdir bin bin/rc bin/mips bin/386 bin/power bin/arm
|
mkdir bin bin/rc bin/mips bin/386 bin/power bin/arm
|
||||||
mkdir lib tmp
|
mkdir lib tmp
|
||||||
|
touch lib/webcookies
|
||||||
|
chmod 600 lib/webcookies
|
||||||
chmod +t tmp
|
chmod +t tmp
|
||||||
bind -qc /n/other/usr/$user/tmp $home/tmp
|
bind -qc /n/other/usr/$user/tmp $home/tmp
|
||||||
bind -c $home/tmp /tmp
|
bind -c $home/tmp /tmp
|
||||||
|
|
||||||
mail -c
|
mail -c
|
||||||
auth/cron -c
|
auth/cron -c
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@ bind -c $x^home/tmp /tmp
|
||||||
font = /lib/font/bit/pelm/euro.9.font
|
font = /lib/font/bit/pelm/euro.9.font
|
||||||
switch($x^service){
|
switch($x^service){
|
||||||
case terminal
|
case terminal
|
||||||
|
webcookies
|
||||||
|
webfs
|
||||||
plumber
|
plumber
|
||||||
startupasfs
|
startupasfs
|
||||||
echo -n accelerated > '#m/mousectl'
|
echo -n accelerated > '#m/mousectl'
|
||||||
|
|
|
@ -4,19 +4,20 @@ hget \- retrieve a web page corresponding to a url
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B hget
|
.B hget
|
||||||
[
|
[
|
||||||
.B -dhv
|
|
||||||
] [
|
|
||||||
.B -o
|
.B -o
|
||||||
.I ofile
|
.I file
|
||||||
] [
|
] [
|
||||||
.B -p
|
.B -p
|
||||||
.I body
|
.I body
|
||||||
] [
|
] [
|
||||||
.B -x
|
|
||||||
.I netmntpt
|
|
||||||
] [
|
|
||||||
.B -r
|
.B -r
|
||||||
.I header
|
.I header
|
||||||
|
] [
|
||||||
|
.B -m
|
||||||
|
.I method
|
||||||
|
] [
|
||||||
|
.B -b
|
||||||
|
.I baseurl
|
||||||
]
|
]
|
||||||
.I url
|
.I url
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
|
@ -26,7 +27,16 @@ retrieves the web page specified by the URL
|
||||||
and writes it, absent the
|
and writes it, absent the
|
||||||
.B -o
|
.B -o
|
||||||
option, to standard output.
|
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
|
.PP
|
||||||
If
|
If
|
||||||
.I url
|
.I url
|
||||||
|
@ -47,40 +57,22 @@ but incomplete,
|
||||||
will fetch the missing bytes.
|
will fetch the missing bytes.
|
||||||
.PP
|
.PP
|
||||||
Option
|
Option
|
||||||
.B -h
|
|
||||||
causes HTTP headers to be printed to standard output
|
|
||||||
in addition to the transferred web page.
|
|
||||||
.PP
|
|
||||||
Option
|
|
||||||
.B -r
|
.B -r
|
||||||
sends an arbitrary HTTP
|
sends an arbitrary HTTP
|
||||||
.IR header .
|
.IR header .
|
||||||
.PP
|
.PP
|
||||||
Option
|
Option
|
||||||
.B -d
|
.B -m
|
||||||
turns on debugging written to standard error.
|
overrides the HTTP method used for the request.
|
||||||
.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.
|
|
||||||
.SH SOURCE
|
.SH SOURCE
|
||||||
.B /sys/src/cmd/hget.c
|
.B /rc/bin/hget
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
|
.IR webfs (4),
|
||||||
.IR ftpfs (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
|
.B cookiefs
|
||||||
decides not to accept the cookie (as outlined in
|
decides not to accept the cookie (as outlined in
|
||||||
RFC2109, section 4.3.4), no indication is given.
|
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
|
.SH SOURCE
|
||||||
.B /sys/src/cmd/webcookies.c
|
.B /sys/src/cmd/webcookies.c
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
|
.IR webfs (4),
|
||||||
.IR hget (1)
|
.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
|
.SH SYNOPSIS
|
||||||
.B webfs
|
.B webfs
|
||||||
[
|
[
|
||||||
.B -c
|
|
||||||
.I cookiefile
|
|
||||||
]
|
|
||||||
[
|
|
||||||
.B -m
|
.B -m
|
||||||
.I mtpt
|
.I mtpt
|
||||||
]
|
]
|
||||||
|
@ -26,10 +22,15 @@ mounts itself at
|
||||||
.BR /mnt/web ),
|
.BR /mnt/web ),
|
||||||
and, if
|
and, if
|
||||||
.I service
|
.I service
|
||||||
is specified, will post a service file descriptor
|
is specified, will post a service file descriptor in
|
||||||
in
|
|
||||||
.BR /srv/\fIservice .
|
.BR /srv/\fIservice .
|
||||||
.PP
|
.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
|
.I Webfs
|
||||||
presents a three-level file system suggestive
|
presents a three-level file system suggestive
|
||||||
of the network protocol hierarchies
|
of the network protocol hierarchies
|
||||||
|
@ -37,13 +38,12 @@ of the network protocol hierarchies
|
||||||
and
|
and
|
||||||
.IR ether (3).
|
.IR ether (3).
|
||||||
.PP
|
.PP
|
||||||
The top level contains three files:
|
The top level contains the files files:
|
||||||
.BR ctl ,
|
.BR ctl ,
|
||||||
.BR cookies ,
|
|
||||||
and
|
and
|
||||||
.BR clone .
|
.BR clone .
|
||||||
.PP
|
.PP
|
||||||
The
|
The top level
|
||||||
.B ctl
|
.B ctl
|
||||||
file is used to maintain parameters global to the instance of
|
file is used to maintain parameters global to the instance of
|
||||||
.IR webfs .
|
.IR webfs .
|
||||||
|
@ -53,72 +53,6 @@ file yields the current values of the parameters.
|
||||||
Writing strings of the form
|
Writing strings of the form
|
||||||
.RB `` attr " " value ''
|
.RB `` attr " " value ''
|
||||||
sets a particular attribute.
|
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
|
The top-level directory also contains
|
||||||
numbered directories corresponding to connections, which
|
numbered directories corresponding to connections, which
|
||||||
may be used to fetch a single URL.
|
may be used to fetch a single URL.
|
||||||
|
@ -131,23 +65,10 @@ After opening, the
|
||||||
.B clone
|
.B clone
|
||||||
file is equivalent to the file
|
file is equivalent to the file
|
||||||
.IB n /ctl \fR.
|
.IB n /ctl \fR.
|
||||||
A connection is assumed closed once all files in its directory
|
A connection is assumed closed once all files in its
|
||||||
have been closed, and is then will be reallocated.
|
directory have been closed, and is then will be reallocated.
|
||||||
.PP
|
.PP
|
||||||
Each connection has its own private set of
|
Each connection has a URL attribute
|
||||||
.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
|
|
||||||
.B url
|
.B url
|
||||||
associated with it.
|
associated with it.
|
||||||
This URL may be an absolute URL such as
|
This URL may be an absolute URL such as
|
||||||
|
@ -156,153 +77,96 @@ or a relative URL such as
|
||||||
.IR ../index.html .
|
.IR ../index.html .
|
||||||
The
|
The
|
||||||
.B baseurl
|
.B baseurl
|
||||||
string variable sets the URL against which relative URLs
|
attribute sets the URL against which relative URLs
|
||||||
are interpreted.
|
are interpreted.
|
||||||
Once the URL has been set,
|
Once the URL has been set by wrting to the
|
||||||
its pieces can be retrieved via individual files in the
|
.B ctl
|
||||||
|
file of the connetcion, its pieces can be retrieved via
|
||||||
|
individual files in the
|
||||||
.B parsed
|
.B parsed
|
||||||
directory.
|
directory:
|
||||||
.I Webfs
|
.de UU
|
||||||
parses the following URL syntaxes; names in italics are
|
.TP
|
||||||
the names of files in the
|
.B parsed/\fI\\$1
|
||||||
.B parsed
|
\\$2
|
||||||
directory.
|
..
|
||||||
.IP
|
.UU url http://pete:secret@www.example.com:8000/cgi/search?q=kittens#results
|
||||||
\fIscheme\f5:\fIschemedata
|
.UU scheme http
|
||||||
.br
|
.UU user pete
|
||||||
\f5http://\fIhost\f5/\fIpath\fR[\f5?\fIquery\fR][\f5#\fIfragment\fR]
|
.UU pass secret
|
||||||
.br
|
.UU host www.example.com
|
||||||
\f5ftp://\fR[\fIuser\fR[\f5:\fIpassword\fR]\f5@\fR]\fP\f5\fIhost\f5/\fIpath\fR[\f5;type=\fIftptype\fR]
|
.UU port 8000
|
||||||
.br
|
.UU path /cgi/search
|
||||||
\f5file:\fIpath
|
.UU query q=kittens
|
||||||
.LP
|
.UU fragment results
|
||||||
If there is associated data to be
|
.PP
|
||||||
posted with the request, it can be written to
|
If there is associated data to be posted with the request,
|
||||||
|
it can be written to
|
||||||
.BR postbody .
|
.BR postbody .
|
||||||
Finally, opening
|
Opening
|
||||||
|
.B postbody
|
||||||
|
or
|
||||||
.B body
|
.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
|
The resulting data may be read from
|
||||||
.B body
|
.B body
|
||||||
as it arrives.
|
as it arrives.
|
||||||
After the request has been executed, the MIME content type
|
.PP
|
||||||
may be read from the
|
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
|
.B contenttype
|
||||||
file.
|
Sets the MIME content type of the postbody.
|
||||||
.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:
|
|
||||||
.TP
|
.TP
|
||||||
.BI name= name
|
.B request
|
||||||
The name of the cookie on the remote server.
|
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
|
.TP
|
||||||
.BI value= value
|
.B headers
|
||||||
The value associated with that name on the remote server.
|
Adds arbitrary HTTP headers to be send with
|
||||||
The actual data included when a cookie is sent back
|
the request.
|
||||||
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
|
|
||||||
.SH EXAMPLE
|
.SH EXAMPLE
|
||||||
.B /sys/src/cmd/webfs/webget.c
|
.B /rc/bin/hget
|
||||||
is a simple client.
|
is a simple client.
|
||||||
.SH SOURCE
|
.SH SOURCE
|
||||||
.B /sys/src/cmd/webfs
|
.B /sys/src/cmd/webfs
|
||||||
.SH SEE ALSO
|
.SH "SEE ALSO"
|
||||||
.IR hget (1),
|
.IR webcookies (4),
|
||||||
.IR webcookies (4)
|
.IR hget (1)
|
||||||
.SH BUGS
|
.SH DIAGNOSTICS
|
||||||
It's not clear what the relationship between
|
For cookies to work,
|
||||||
.IR hget ,
|
.IR webcookies (4),
|
||||||
.I webcookies
|
should be running and mounted on
|
||||||
and
|
.B /mnt/webcookies
|
||||||
.I webfs
|
otherwise cookies will be ignored.
|
||||||
should be.
|
|
||||||
|
|
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 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 */
|
typedef struct {
|
||||||
struct Ibuf
|
char *s1;
|
||||||
{
|
char *s2;
|
||||||
int fd;
|
} Str2;
|
||||||
Ioproc *io;
|
|
||||||
char buf[4096];
|
|
||||||
char *rp, *wp;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Ctl
|
/* 9p */
|
||||||
{
|
typedef struct Req Req;
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Url
|
struct Url
|
||||||
{
|
{
|
||||||
int ischeme;
|
char *scheme;
|
||||||
char* url;
|
char *user;
|
||||||
char* scheme;
|
char *pass;
|
||||||
int (*open)(Client*, Url*);
|
char *host;
|
||||||
int (*read)(Client*, Req*);
|
char *port;
|
||||||
void (*close)(Client*);
|
char *path;
|
||||||
char* schemedata;
|
char *query;
|
||||||
char* authority;
|
char *fragment;
|
||||||
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;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
struct Key
|
||||||
extern int cookiedebug;
|
{
|
||||||
extern Srv fs;
|
Key *next;
|
||||||
extern int fsdebug;
|
char *val;
|
||||||
extern Ctl globalctl;
|
char key[];
|
||||||
extern int nclient;
|
};
|
||||||
extern int urldebug;
|
|
||||||
extern int httpdebug;
|
|
||||||
extern char* status[];
|
|
||||||
|
|
||||||
|
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 */
|
/* sub */
|
||||||
void initibuf(Ibuf*, Ioproc*, int);
|
void* emalloc(int n);
|
||||||
int readibuf(Ibuf*, char*, int);
|
char* estrdup(char *s);
|
||||||
void unreadline(Ibuf*, char*);
|
|
||||||
int readline(Ibuf*, char*, int);
|
|
||||||
|
|
||||||
/* client.c */
|
Key* addkey(Key *h, char *key, char *val);
|
||||||
int newclient(int);
|
Key* delkey(Key *h, char *key);
|
||||||
void closeclient(Client*);
|
char* lookkey(Key *k, char *key);
|
||||||
void clonectl(Ctl*);
|
Key* parsehdr(char *s);
|
||||||
int ctlwrite(Req*, Ctl*, char*, char*);
|
char* unquote(char *s, char **ps);
|
||||||
int clientctlwrite(Req*, Client*, char*, char*);
|
|
||||||
int globalctlwrite(Req*, char*, char*);
|
|
||||||
void ctlread(Req*, Client*);
|
|
||||||
void globalctlread(Req*);
|
|
||||||
void plumburl(char*, char*);
|
|
||||||
|
|
||||||
/* cookies.c */
|
/* url */
|
||||||
void cookieread(Req*);
|
#pragma varargck type "U" Url*
|
||||||
void cookiewrite(Req*);
|
#pragma varargck type "E" Str2
|
||||||
void cookieopen(Req*);
|
|
||||||
void cookieclunk(Fid*);
|
|
||||||
void initcookies(char*);
|
|
||||||
void closecookies(void);
|
|
||||||
void httpsetcookie(char*, char*, char*);
|
|
||||||
char* httpcookies(char*, char*, int);
|
|
||||||
|
|
||||||
/* fs.c */
|
int Efmt(Fmt*);
|
||||||
void initfs(void);
|
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 */
|
/* buq */
|
||||||
int httpopen(Client*, Url*);
|
int buread(Buq *q, void *v, int l);
|
||||||
int httpread(Client*, Req*);
|
int buwrite(Buq *q, void *v, int l);
|
||||||
void httpclose(Client*);
|
void buclose(Buq *q, char *error);
|
||||||
|
Buq* bualloc(int limit);
|
||||||
|
void bufree(Buq *q);
|
||||||
|
|
||||||
/* io.c */
|
void bureq(Buq *q, Req *r);
|
||||||
int iotlsdial(Ioproc*, char*, char*, char*, int*, int);
|
void buflushreq(Buq *q, Req *r);
|
||||||
int ioprint(Ioproc*, int, char*, ...);
|
|
||||||
#pragma varargck argpos ioprint 3
|
|
||||||
|
|
||||||
/* plumb.c */
|
/* http */
|
||||||
void plumbinit(void);
|
void flushauth(Url *u, char *t);
|
||||||
void plumbstart(void);
|
void http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost);
|
||||||
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*);
|
|
||||||
|
|
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
|
</$objtype/mkfile
|
||||||
BIN=/$objtype/bin
|
BIN=/$objtype/bin
|
||||||
|
|
||||||
TARG=webfs
|
TARG=webfs
|
||||||
|
|
||||||
SCHEMEOFILES=\
|
HFILES=fns.h dat.h
|
||||||
file.$O\
|
OFILES=sub.$O url.$O buq.$O http.$O fs.$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/%}\
|
|
||||||
|
|
||||||
</sys/src/cmd/mkone
|
</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…
Add table
Add a link
Reference in a new issue