ref: 36a8d961bf90a5b30e7fc9dedb53f07d485ef41f
parent: 69115adfe4050c7e0e88b26aea77d6dc829296d3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jun 1 09:39:37 EDT 2025
webfs: Provide errorbody file Have a way to read the error response body from the request.
--- a/sys/man/4/webfs
+++ b/sys/man/4/webfs
@@ -166,8 +166,19 @@
.B parsed
directory will change to the final destination.
.PP
+Opening the
+.B body
+file can fail, returning HTTP status error in the
+error string.
+If more detailed error is required, the
+.B errorbody
+file can be opend, providing the servers error
+response (usually formatted as HTML).
+.PP
The resulting data may be read from
.B body
+and
+.B errorbody
as it arrives.
.PP
The following is a list of attributes that can be
--- a/sys/src/cmd/webfs/buq.c
+++ b/sys/src/cmd/webfs/buq.c
@@ -156,6 +156,15 @@
}
void
+busethdrs(Buq *q, Url *u, Key *h)
+{
+ qlock(q);
+ q->hdr = h;
+ q->url = u;
+ qunlock(q);
+}
+
+void
buclose(Buq *q, char *error)
{
if(q == nil)
--- a/sys/src/cmd/webfs/fns.h
+++ b/sys/src/cmd/webfs/fns.h
@@ -28,6 +28,7 @@
void freeurl(Url *u);
/* buq */
+void busethdrs(Buq *q, Url *u, Key *h);
int buread(Buq *q, void *v, int l);
int buwrite(Buq *q, void *v, int l);
void buclose(Buq *q, char *error);
@@ -40,4 +41,4 @@
/* http */
int authenticate(Url *u, Url *ru, char *method, char *s);
void flushauth(Url *u, char *t);
-void http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost);
+void http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost, Buq *qerror);
--- a/sys/src/cmd/webfs/fs.c
+++ b/sys/src/cmd/webfs/fs.c
@@ -23,6 +23,7 @@
int obody; /* body opend */
int cbody; /* body closed */
Buq *qbody;
+ Buq *qerror;
};
struct Webfid
@@ -31,7 +32,7 @@
Client *client;
Key *key; /* copy for Qheader */
- Buq *buq; /* reference for Qbody, Qpost */
+ Buq *buq; /* reference for Qbody, Qpost, Qerror */
};
enum {
@@ -42,6 +43,7 @@
Qctl,
Qbody,
Qpost,
+ Qerror,
Qparsed,
Qurl,
Qurlschm,
@@ -63,6 +65,7 @@
"ctl",
"body",
"postbody",
+ "errorbody",
"parsed",
"url",
"scheme",
@@ -107,6 +110,7 @@
cl->url = nil;
cl->hdr = nil;
cl->qbody = nil;
+ cl->qerror = nil;
return cl;
}
@@ -119,8 +123,10 @@
if(cl == nil || decref(cl))
return;
- buclose(cl->qbody, 0);
+ buclose(cl->qbody, nil);
+ buclose(cl->qerror, nil);
bufree(cl->qbody);
+ bufree(cl->qerror);
while(k = cl->hdr){
cl->hdr = k->next;
@@ -138,6 +144,8 @@
{
static Url nullurl;
+ if(cl->qerror && cl->qerror->url)
+ return cl->qerror->url;
if(cl->qbody && cl->qbody->url)
return cl->qbody->url;
if(cl->url)
@@ -145,6 +153,16 @@
return &nullurl;
}
+static Key*
+clienthdrs(Client *cl)
+{
+ if(cl->qerror && cl->qerror->hdr)
+ return cl->qerror->hdr;
+ if(cl->qbody && cl->qbody->hdr)
+ return cl->qbody->hdr;
+ return nil;
+}
+
static void*
wfaux(Webfid *f)
{
@@ -307,13 +325,13 @@
break;
}
}
- if(i == Qheader && f->client && f->client->qbody){
+ if(i == Qheader && f->client){
char buf[128];
Key *k;
- for(k = f->client->qbody->hdr; k; k = k->next){
+ for(k = clienthdrs(f->client); k; k = k->next){
nstrcpy(buf, k->key, sizeof(buf));
- if(!strcmp(name, fshdrname(buf)))
+ if(strcmp(name, fshdrname(buf)) == 0)
break;
}
if(k != nil){
@@ -377,8 +395,13 @@
if(cl->obody)
goto Inuse;
if(cl->cbody){
+ buclose(cl->qerror, nil);
+ bufree(cl->qerror);
+ cl->qerror = nil;
+ buclose(cl->qbody, nil);
bufree(cl->qbody);
cl->qbody = nil;
+
cl->cbody = 0;
}
if(cl->qbody == nil){
@@ -389,7 +412,7 @@
return;
}
cl->qbody = bualloc(16*1024);
- if(f->level != Qbody){
+ if(f->level == Qpost){
f->buq = bualloc(64*1024);
if(!lookkey(cl->hdr, "Content-Type"))
cl->hdr = addkey(cl->hdr, "Content-Type",
@@ -413,7 +436,8 @@
if(agent && !lookkey(cl->hdr, "User-Agent"))
cl->hdr = addkey(cl->hdr, "User-Agent", agent);
- http(m, cl->url, cl->hdr, cl->qbody, f->buq);
+ cl->qerror = bualloc(16*1024);
+ http(m, cl->url, cl->hdr, cl->qbody, f->buq, cl->qerror);
cl->request[0] = 0;
cl->url = nil;
cl->hdr = nil;
@@ -424,6 +448,16 @@
incref(cl->qbody);
bureq(f->buq = cl->qbody, r);
return;
+ case Qerror:
+ if(cl->qerror == nil){
+ respond(r, "request not started");
+ return;
+ }
+ if(f->buq)
+ break;
+ incref(cl->qerror);
+ f->buq = cl->qerror;
+ break;
}
respond(r, nil);
}
@@ -453,9 +487,9 @@
Key *k;
i -= Qparsed+1;
- if(cl == nil || cl->qbody == nil)
+ if(cl == nil)
return -1;
- for(k = cl->qbody->hdr; i > 0 && k; i--, k = k->next)
+ for(k = clienthdrs(cl); i > 0 && k; i--, k = k->next)
;
if(k == nil || i > 0)
return -1;
@@ -520,6 +554,7 @@
urlstr(buf, sizeof(buf), clienturl(f->client), f->level);
goto String;
case Qbody:
+ case Qerror:
bureq(f->buq, r);
return;
}
@@ -707,7 +742,7 @@
if(f = fid->aux){
fid->aux = nil;
if(f->buq){
- buclose(f->buq, 0);
+ buclose(f->buq, nil);
if(f->client->qbody == f->buq){
f->client->obody = 0;
f->client->cbody = 1;
@@ -714,8 +749,7 @@
}
bufree(f->buq);
}
- if(f->key)
- free(f->key);
+ if(f->key) free(f->key);
freeclient(f->client);
free(f);
}
--- a/sys/src/cmd/webfs/http.c
+++ b/sys/src/cmd/webfs/http.c
@@ -546,7 +546,7 @@
#define NOLENGTH 0x7fffffffffffffffLL
void
-http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost)
+http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost, Buq *qerror)
{
int i, l, n, try, pid, fd, cfd, needlength, chunked, retry, nobody, badauth;
char *s, *x, buf[IOUNIT+2], status[256], method[16], *host;
@@ -558,6 +558,7 @@
incref(qbody);
if(qpost) incref(qpost);
+ incref(qerror);
nstrcpy(method, m, sizeof(method));
switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
default:
@@ -567,6 +568,8 @@
bufree(qbody);
buclose(qpost, "can't fork");
bufree(qpost);
+ buclose(qerror, "can't fork");
+ bufree(qerror);
while(k = shdr){
shdr = k->next;
free(k);
@@ -875,6 +878,11 @@
case 504: /* Gateway Timeout */
case 505: /* HTTP Version not Supported */
Error:
+ if(!retry){
+ busethdrs(qerror, u, rhdr);
+ rhdr = nil;
+ u = nil;
+ }
h->cancel = 1;
buclose(qbody, status);
buclose(qpost, status);
@@ -887,7 +895,7 @@
waitpid();
pid = 0;
}
- buclose(qpost, 0);
+ buclose(qpost, nil);
bufree(qpost);
qpost = nil;
}
@@ -956,10 +964,12 @@
case 206: /* Partial Content */
if(h->tunnel)
break;
- qbody->url = u; u = nil;
- qbody->hdr = rhdr; rhdr = nil;
+ busethdrs(qbody, u, rhdr);
+ rhdr = nil;
+ u = nil;
+ buclose(qerror, nil); /* no error */
if(nobody)
- buclose(qbody, 0);
+ buclose(qbody, nil);
break;
}
@@ -998,9 +1008,9 @@
* skipping the error page so we wont touch qbody.
*/
while(!nobody){
- if((qbody->closed || retry) && !h->keep)
+ if((qerror->closed && qbody->closed || retry) && !h->keep)
break;
- if(chunked){
+ if(chunked){
if(hline(h, buf, sizeof(buf)-1, 0) <= 0)
break;
length = strtoll(buf, nil, 16);
@@ -1014,7 +1024,7 @@
break;
offset += n;
if(!retry)
- if(buwrite(qbody, buf, n) != n)
+ if(buwrite(qerror->closed?qbody:qerror, buf, n) != n)
break;
}
if(offset != length){
@@ -1035,8 +1045,10 @@
if(length > 0)
continue;
}
- if(!retry)
- buclose(qbody, 0);
+ if(!retry){
+ buclose(qerror, nil);
+ buclose(qbody, nil);
+ }
break;
}
@@ -1053,6 +1065,9 @@
h = nil;
}
alarm(0);
+ buclose(qerror, nil);
+ bufree(qerror);
+
snprint(buf, sizeof(buf), "%s %r", status);
buclose(qbody, buf);
bufree(qbody);
--
⑨