コード例 #1
0
static int
fetch_chunked(struct worker *wrk, struct http_conn *htc)
{
	int i;
	char buf[20];		/* XXX: 20 is arbitrary */
	unsigned u;
	ssize_t cl;

	assert(wrk->busyobj->body_status == BS_CHUNKED);
	do {
		/* Skip leading whitespace */
		do {
			if (HTC_Read(wrk, htc, buf, 1) <= 0)
				return (-1);
		} while (vct_islws(buf[0]));

		if (!vct_ishex(buf[0]))
			return (FetchError(wrk,"chunked header non-hex"));

		/* Collect hex digits, skipping leading zeros */
		for (u = 1; u < sizeof buf; u++) {
			do {
				if (HTC_Read(wrk, htc, buf + u, 1) <= 0)
					return (-1);
			} while (u == 1 && buf[0] == '0' && buf[u] == '0');
			if (!vct_ishex(buf[u]))
				break;
		}

		if (u >= sizeof buf)
			return (FetchError(wrk,"chunked header too long"));

		/* Skip trailing white space */
		while(vct_islws(buf[u]) && buf[u] != '\n')
			if (HTC_Read(wrk, htc, buf + u, 1) <= 0)
				return (-1);

		if (buf[u] != '\n')
			return (FetchError(wrk,"chunked header no NL"));

		buf[u] = '\0';
		cl = fetch_number(buf, 16);
		if (cl < 0)
			return (FetchError(wrk,"chunked header number syntax"));

		if (cl > 0 && wrk->busyobj->vfp->bytes(wrk, htc, cl) <= 0)
			return (-1);

		i = HTC_Read(wrk, htc, buf, 1);
		if (i <= 0)
			return (-1);
		if (buf[0] == '\r' && HTC_Read(wrk, htc, buf, 1) <= 0)
			return (-1);
		if (buf[0] != '\n')
			return (FetchError(wrk,"chunked tail no NL"));
	} while (cl > 0);
	return (0);
}
コード例 #2
0
static int
fetch_straight(struct sess *sp, struct http_conn *htc, const char *b)
{
	int i;
	ssize_t cl;

	assert(sp->wrk->body_status == BS_LENGTH);

	cl = fetch_number(b, 10);
	sp->wrk->vfp->begin(sp, cl > 0 ? cl : 0);
	if (cl < 0) {
		WSP(sp, SLT_FetchError, "straight length field bogus");
		return (-1);
	} else if (cl == 0)
		return (0);

	i = sp->wrk->vfp->bytes(sp, htc, cl);
	if (i <= 0) {
		WSP(sp, SLT_FetchError, "straight read_error: %d %d (%s)",
		    i, errno, htc->error);
		return (-1);
	}
	return (0);
}
コード例 #3
0
int
FetchBody(struct worker *wrk, struct object *obj)
{
	int cls;
	struct storage *st;
	int mklen;
	ssize_t cl;
	struct http_conn *htc;
	struct busyobj *bo;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	bo = wrk->busyobj;
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	AZ(bo->fetch_obj);
	CHECK_OBJ_NOTNULL(bo->vbc, VBC_MAGIC);
	CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(obj->http, HTTP_MAGIC);

	htc = &bo->htc;

	if (bo->vfp == NULL)
		bo->vfp = &vfp_nop;

	AssertObjCorePassOrBusy(obj->objcore);

	AZ(bo->vgz_rx);
	AZ(VTAILQ_FIRST(&obj->store));

	bo->fetch_obj = obj;
	bo->fetch_failed = 0;

	/* XXX: pick up estimate from objdr ? */
	cl = 0;
	switch (bo->body_status) {
	case BS_NONE:
		cls = 0;
		mklen = 0;
		break;
	case BS_ZERO:
		cls = 0;
		mklen = 1;
		break;
	case BS_LENGTH:
		cl = fetch_number(bo->h_content_length, 10);
		bo->vfp->begin(wrk, cl > 0 ? cl : 0);
		cls = fetch_straight(wrk, htc, cl);
		mklen = 1;
		if (bo->vfp->end(wrk))
			cls = -1;
		break;
	case BS_CHUNKED:
		bo->vfp->begin(wrk, cl);
		cls = fetch_chunked(wrk, htc);
		mklen = 1;
		if (bo->vfp->end(wrk))
			cls = -1;
		break;
	case BS_EOF:
		bo->vfp->begin(wrk, cl);
		cls = fetch_eof(wrk, htc);
		mklen = 1;
		if (bo->vfp->end(wrk))
			cls = -1;
		break;
	case BS_ERROR:
		cls = 1;
		mklen = 0;
		break;
	default:
		cls = 0;
		mklen = 0;
		INCOMPL();
	}
	AZ(bo->vgz_rx);

	/*
	 * It is OK for ->end to just leave the last storage segment
	 * sitting on wrk->storage, we will always call vfp_nop_end()
	 * to get it trimmed or thrown out if empty.
	 */
	AZ(vfp_nop_end(wrk));

	bo->fetch_obj = NULL;

	WSLB(wrk, SLT_Fetch_Body, "%u(%s) cls %d mklen %d",
	    bo->body_status, body_status(bo->body_status),
	    cls, mklen);

	if (bo->body_status == BS_ERROR) {
		VDI_CloseFd(wrk, &bo->vbc);
		return (__LINE__);
	}

	if (cls < 0) {
		wrk->stats.fetch_failed++;
		/* XXX: Wouldn't this store automatically be released ? */
		while (!VTAILQ_EMPTY(&obj->store)) {
			st = VTAILQ_FIRST(&obj->store);
			VTAILQ_REMOVE(&obj->store, st, list);
			STV_free(st);
		}
		VDI_CloseFd(wrk, &bo->vbc);
		obj->len = 0;
		return (__LINE__);
	}
	AZ(bo->fetch_failed);

	if (cls == 0 && bo->should_close)
		cls = 1;

	WSLB(wrk, SLT_Length, "%zd", obj->len);

	{
	/* Sanity check fetch methods accounting */
		ssize_t uu;

		uu = 0;
		VTAILQ_FOREACH(st, &obj->store, list)
			uu += st->len;
		if (bo->do_stream)
			/* Streaming might have started freeing stuff */
			assert (uu <= obj->len);

		else
			assert(uu == obj->len);
	}

	if (mklen > 0) {
		http_Unset(obj->http, H_Content_Length);
		http_PrintfHeader(wrk, bo->vbc->vsl_id, obj->http,
		    "Content-Length: %zd", obj->len);
	}

	if (cls)
		VDI_CloseFd(wrk, &bo->vbc);
	else
		VDI_RecycleFd(wrk, &bo->vbc);

	return (0);
}
コード例 #4
0
static int
fetch_chunked(struct sess *sp, struct http_conn *htc)
{
	int i;
	char buf[20];		/* XXX: 20 is arbitrary */
	unsigned u;
	ssize_t cl;

	sp->wrk->vfp->begin(sp, 0);
	assert(sp->wrk->body_status == BS_CHUNKED);
	do {
		/* Skip leading whitespace */
		do {
			i = HTC_Read(htc, buf, 1);
			CERR();
		} while (vct_islws(buf[0]));

		/* Collect hex digits, skipping leading zeros */
		for (u = 1; u < sizeof buf; u++) {
			do {
				i = HTC_Read(htc, buf + u, 1);
				CERR();
			} while (u == 1 && buf[0] == '0' && buf[u] == '0');
			if (!vct_ishex(buf[u]))
				break;
		}

		if (u >= sizeof buf) {
			WSP(sp, SLT_FetchError,	"chunked header too long");
			return (-1);
		}

		/* Skip trailing white space */
		while(vct_islws(buf[u]) && buf[u] != '\n') {
			i = HTC_Read(htc, buf + u, 1);
			CERR();
		}

		if (buf[u] != '\n') {
			WSP(sp, SLT_FetchError,	"chunked header char syntax");
			return (-1);
		}
		buf[u] = '\0';

		cl = fetch_number(buf, 16);
		if (cl < 0) {
			WSP(sp, SLT_FetchError,	"chunked header nbr syntax");
			return (-1);
		} else if (cl > 0) {
			i = sp->wrk->vfp->bytes(sp, htc, cl);
			CERR();
		}
		i = HTC_Read(htc, buf, 1);
		CERR();
		if (buf[0] == '\r') {
			i = HTC_Read(htc, buf, 1);
			CERR();
		}
		if (buf[0] != '\n') {
			WSP(sp, SLT_FetchError,	"chunked tail syntax");
			return (-1);
		}
	} while (cl > 0);
	return (0);
}
コード例 #5
0
ファイル: rawdofmt.c プロジェクト: michalsc/AROS
APTR InternalRawDoFmt(CONST_STRPTR FormatString, APTR DataStream, VOID_FUNC PutChProc,
		      APTR inPutChData, va_list VaListStream)
{
#if defined(mc68000)
    /* Frequently, AmigaOS users of RawDoFmt() rely upon the AmigaOS
     * behaviour that A3 *in this routine* is the pointer to PutChData,
     * *and* that it can be modified in PutChProc.
     */
    register volatile UBYTE  *PutChData asm("%a3");
#else
    UBYTE *PutChData = inPutChData;
#endif

    /* As long as there is something to format left */
    while (*FormatString)
    {
	/* Check for '%' sign */
	if (*FormatString == '%')
	{
	    /*
		left	 - left align flag
		fill	 - pad character
		minus	 - 1: number is negative
		minwidth - minimum width
		maxwidth - maximum width
		size	 - one of 'h', 'l', 'i'.
		width	 - width of printable string
		buf	 - pointer to printable string
	    */
	    int left  = 0;
	    int fill  = ' ';
	    int minus = 0;
	    int size  = 'h';
	    ULONG minwidth = 0;
	    ULONG maxwidth = ~0;
	    ULONG width    = 0;
	    UBYTE *buf;

            /* Number of decimal places required to convert a unsigned long to
               ascii. The formula is: ceil(number_of_bits*log10(2)).
	       Since I can't do this here I use .302 instead of log10(2) and
	       +1 instead of ceil() which most often leads to exactly the
	       same result (and never becomes smaller).

	       Note that when the buffer is large enough for decimal it's
	       large enough for hexadecimal as well.  */

	    #define CBUFSIZE (sizeof(IPTR)*8*302/1000+1)
	    /* The buffer for converting long to ascii.  */
	    UBYTE cbuf[CBUFSIZE];
	    ULONG i;

	    /* Skip over '%' character */
	    FormatString++;

	    /* '-' modifier? (left align) */
	    if (*FormatString == '-')
		left = *FormatString++;

	    /* '0' modifer? (pad with zeros) */
	    if (*FormatString == '0')
		fill = *FormatString++;

	    /* Get minimal width */
	    while (*FormatString >= '0' && *FormatString <= '9')
	    {
	        minwidth = minwidth * 10 + (*FormatString++ - '0');
	    }

	    /* Dot following width modifier? */
	    if(*FormatString == '.')
	    {
		FormatString++;
		/* Get maximum width */

		if(*FormatString >= '0' && *FormatString <= '9')
		{
		    maxwidth = 0;
		    do
			maxwidth = maxwidth *10 + (*FormatString++ - '0');
		    while (*FormatString >= '0' && *FormatString <= '9');
		}
	    }

	    /* size modifiers */
	    switch (*FormatString)
	    {
	    case 'l':
	    case 'i':
	    	size = *FormatString++;
		break;
	    }

	    /* Switch over possible format characters. Sets minus, width and buf. */
	    switch(*FormatString)
	    {
		/* BCPL string */
		case 'b':
                {
                    BSTR s = fetch_arg(BSTR);
                    
                    if (s)
                    {
		    	buf = AROS_BSTR_ADDR(s);
		    	width = AROS_BSTR_strlen(s);
		    }
		    else
		    {
		    	buf = "";
		    	width = 0;
		    }

		    break;
                }

		/* C string */
		case 's':
  		    buf = fetch_arg(UBYTE *);

                    if (!buf)
                        buf = "";
		    width = strlen(buf);

		    break;
		{
		    IPTR number = 0; int base;
		    static const char digits[] = "0123456789ABCDEF";

		    case 'p':
		    case 'P':
			fill = '0';
			minwidth = sizeof(APTR)*2;
			size = 'i';
		    case 'x':
		    case 'X':
		        base   = 16;
			number = fetch_number(size, 1);

                        goto do_number;

		    case 'd':
		    case 'D':
		        base   = 10;
  		        number = fetch_number(size, -1);
			minus  = (SIPTR)number < 0;

			if (minus) number = -number;

			goto do_number;

		    case 'u':
		    case 'U':
		        base = 10;
  		        number = fetch_number(size, 1);

		    do_number:

		        buf = &cbuf[CBUFSIZE];
			do
			{
  		            *--buf = digits[number % base];
			    number /= base;
		            width++;
			} while (number);

		    break;
		}


		/* single character */
		case 'c':
		    /* Some space for the result */
		    buf   = cbuf;
		    width = 1;

		    *buf = fetch_number(size, 1);

		    break;

		/* '%' before '\0'? */
		case '\0':
		    /*
			This is nonsense - but do something useful:
			Instead of reading over the '\0' reuse the '\0'.
		    */
		    FormatString--;
		    /* Get compiler happy */
		    buf = NULL;
		    break;

		/* Convert '%unknown' to 'unknown'. This includes '%%' to '%'. */
		default:
		    buf   = (UBYTE *)FormatString;
		    width = 1;
		    break;
	    }

	    if (width > maxwidth) width = maxwidth;

	    /* Skip the format character */
	    FormatString++;

	    /*
		Now everything I need is known:
		buf	 - contains the string to be printed
		width	 - the size of the string
		minus	 - is 1 if there is a '-' to print
		fill	 - is the pad character
		left	 - is 1 if the string should be left aligned
		minwidth - is the minimal width of the field
		(maxwidth is already part of width)

		So just print it.
	    */

	    /* Print '-' (if there is one and the pad character is no space) */
	    if (minus && fill != ' ')
	        PutCh('-');

	    /* Pad left if not left aligned */
	    if (!left)
		for (i = width + minus; i < minwidth; i++)
		    PutCh(fill);

	    /* Print '-' (if there is one and the pad character is a space) */
	    if(minus && fill == ' ')
                PutCh('-');

	    /* Print body upto width */
	    for(i=0; i<width; i++) {
	        PutCh(*buf);
		buf++;
	    }

	    /* Pad right if left aligned */
	    if(left)
		for(i = width + minus; i<minwidth; i++)
		    PutCh(fill);
	}
	else
	{