This is just the initial version and it doesn't quite work the way
we need it to yet, but the idea is to be able to say:
sub vcl_fetch {
if (obj.status == 503) {
synthetic {"
<HTML>
<H1>Sorry, could not contact the backend server</H1>
<P>
Try again later.
</P>
<HR>
<PRE>
URL: "} req.url {"
User Agnet: "} req.http.user-agent {"
</PRE>
</HTML>
"};
}
}
A new VCL syntactic element have been introduced to do this: "the
long string". A long string is anything from {" to "}, newlines,
controlcharacters and all. (Normal "..." strings cannot contain
control characters.
Technical details:
Don't NULL terminate string sequences in VRT context, we may have
NULL cropping up as a legal value if a header is missing, add the
magic "vrt_magic_string_end" for terminating string contactenation.
git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3026
d4fa192b-c00b-0410-8231-
f00ffab90ce4
/* cache_hash.c */
void HSH_Prealloc(struct sess *sp);
+void HSH_Freestore(struct object *o);
int HSH_Compare(const struct sess *sp, const struct objhead *o);
void HSH_Copy(const struct sess *sp, const struct objhead *o);
struct object *HSH_Lookup(struct sess *sp);
/* rfc2616.c */
int RFC2616_cache_policy(const struct sess *sp, const struct http *hp);
+/* storage_synth.c */
+struct vsb *SMS_Makesynth(struct object *obj);
+void SMS_Finish(struct object *obj);
+
#define MTX pthread_mutex_t
#define MTX_INIT(foo) AZ(pthread_mutex_init(foo, NULL))
#define MTX_DESTROY(foo) AZ(pthread_mutex_destroy(foo))
CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC);
}
-static void
+void
HSH_Freestore(struct object *o)
{
struct storage *st, *stn;
#include "vcl.h"
#include "cache.h"
+
+void *vrt_magic_string_end = &vrt_magic_string_end;
+
/*--------------------------------------------------------------------*/
void
if (b + 1 < e)
*b++ = ' ';
}
- while (p != NULL) {
+ while (p != vrt_magic_string_end) {
+ if (p == NULL)
+ p = "(null)";
x = strlen(p);
if (b + x < e)
memcpy(b, p, x);
/*--------------------------------------------------------------------*/
+/*lint -e{818} sp could be const */
+void
+VRT_synth_page(struct sess *sp, unsigned flags, const char *str, ...)
+{
+ va_list ap;
+ const char *p;
+ struct vsb *vsb;
+
+ (void)flags;
+ CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
+ vsb = SMS_Makesynth(sp->obj);
+ AN(vsb);
+
+ vsb_cat(vsb, str);
+ va_start(ap, str);
+ p = va_arg(ap, const char *);
+ while (p != vrt_magic_string_end) {
+ if (p == NULL)
+ p = "(null)";
+ vsb_cat(vsb, p);
+ p = va_arg(ap, const char *);
+ }
+ va_end(ap);
+ SMS_Finish(sp->obj);
+ http_Unset(sp->obj->http, H_Content_Length);
+ http_PrintfHeader(sp->wrk, sp->fd, sp->obj->http,
+ "Content-Length: %d", sp->obj->len);
+}
+
+/*--------------------------------------------------------------------*/
+
void
VRT_purge(const char *regexp, int hash)
{
MAC_STAT(sma_balloc, uint64_t, 'i', "SMA bytes allocated")
MAC_STAT(sma_bfree, uint64_t, 'i', "SMA bytes free")
+MAC_STAT(sms_nreq, uint64_t, 'a', "SMS allocator requests")
+MAC_STAT(sms_nobj, uint64_t, 'i', "SMS outstanding allocations")
+MAC_STAT(sms_nbytes, uint64_t, 'i', "SMS outstanding bytes")
+MAC_STAT(sms_balloc, uint64_t, 'i', "SMS bytes allocated")
+MAC_STAT(sms_bfree, uint64_t, 'i', "SMS bytes free")
+
MAC_STAT(backend_req, uint64_t, 'a', "Backend requests made")
MAC_STAT(n_vcl, uint64_t, 'a', "N vcl total")
* A backend probe specification
*/
+extern void *vrt_magic_string_end;
+
struct vrt_backend_probe {
char *request;
double timeout;
void VRT_ESI(struct sess *sp);
void VRT_Rollback(struct sess *sp);
+/* Synthetic pages */
+void VRT_synth_page(struct sess *sp, unsigned flags, const char *, ...);
+
/* Backend related */
void VRT_init_dir_simple(struct cli *, struct director **, const struct vrt_dir_simple *);
void VRT_init_dir_random(struct cli *, struct director **, const struct vrt_dir_random *);
vcc_ErrWhere(tl, tl->t);
return;
}
- Fb(tl, 0, "0);\n");
+ Fb(tl, 0, "vrt_magic_string_end);\n");
break;
default:
vsb_printf(tl->sb,
do
Fb(tl, 0, ", ");
while (vcc_StringVal(tl));
- Fb(tl, 0, " 0);\n");
+ Fb(tl, 0, " vrt_magic_string_end);\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+parse_synthetic(struct tokenlist *tl)
+{
+ vcc_NextToken(tl);
+
+ Fb(tl, 1, "VRT_synth_page(sp, 0, ");
+ if (!vcc_StringVal(tl)) {
+ vcc_ExpectedStringval(tl);
+ return;
+ }
+ do
+ Fb(tl, 0, ", ");
+ while (vcc_StringVal(tl));
+ Fb(tl, 0, " vrt_magic_string_end);\n");
}
/*--------------------------------------------------------------------*/
{ "purge_url", parse_purge_url },
{ "remove", parse_unset }, /* backward compatibility */
{ "set", parse_set },
+ { "synthetic", parse_synthetic },
{ "unset", parse_unset },
{ NULL, NULL }
};
vsb_cat(sb, " * A backend probe specification\n");
vsb_cat(sb, " */\n");
vsb_cat(sb, "\n");
+ vsb_cat(sb, "extern void *vrt_magic_string_end;\n");
+ vsb_cat(sb, "\n");
vsb_cat(sb, "struct vrt_backend_probe {\n");
vsb_cat(sb, " char *request;\n");
vsb_cat(sb, " double timeout;\n");
vsb_cat(sb, "void VRT_ESI(struct sess *sp);\n");
vsb_cat(sb, "void VRT_Rollback(struct sess *sp);\n");
vsb_cat(sb, "\n");
+ vsb_cat(sb, "/* Synthetic pages */\n");
+ vsb_cat(sb, "void VRT_synth_page(struct sess *sp, unsigned flags, const char *, ...);\n");
+ vsb_cat(sb, "\n");
vsb_cat(sb, "/* Backend related */\n");
vsb_cat(sb, "void VRT_init_dir_simple(struct cli *, struct director **, const struct vrt_dir_simple *);\n");
vsb_cat(sb, "void VRT_init_dir_random(struct cli *, struct director **, const struct vrt_dir_random *);\n");
return;
}
+ /* Recognize long-strings */
+ if (*p == '{' && p[1] == '"') {
+ for (q = p + 2; q < sp->e; q++) {
+ if (*q == '"' && q[1] == '}') {
+ vcc_AddToken(tl, CSTR, p, q + 2);
+ p = q + 2;
+ break;
+ }
+ }
+ u = tl->t->e - tl->t->b;
+ u -= 4; /* {" ... "} */
+ tl->t->dec = TlAlloc(tl, u + 1 );
+ AN(tl->t->dec);
+ memcpy(tl->t->dec, tl->t->b + 2, u);
+ tl->t->dec[u] = '\0';
+ if (q < sp->e)
+ continue;
+ vcc_AddToken(tl, EOI, p, p + 2);
+ vsb_printf(tl->sb,
+ "Unterminated long-string, starting at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
/* Match for the fixed tokens (see token.tcl) */
u = vcl_fixed_token(p, &q);