Subversion Repositories SvarDOS

Rev

Rev 339 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 339 Rev 341
1
/*
1
/*
2
 * unpacks a http "chunked" transfer into a raw data stream.
2
 * unpacks a http "chunked" transfer into a raw data stream.
3
 * this file is part of the pkgnet tool from the SvarDOS project.
3
 * this file is part of the pkgnet tool from the SvarDOS project.
4
 *
4
 *
5
 * Copyright (C) 2021 Mateusz Viste
5
 * Copyright (C) 2021 Mateusz Viste
6
 */
6
 */
7
 
7
 
8
#include <stdlib.h>    /* atol() */
8
#include <stdlib.h>    /* atol() */
9
#include <string.h>
9
#include <string.h>
10
 
10
 
11
#include "unchunk.h"
11
#include "unchunk.h"
12
 
12
 
-
 
13
 
13
/* transforms a http CHUNKED stream into actual data, returns the amount of raw data to read */
14
/* transforms a http CHUNKED stream into actual data, returns the amount of
14
int unchunk(unsigned char *buff, int bufflen) {
-
 
15
  static long bytesleft; /* how many bytes are expected yet in the ongoing chunk */
15
 * raw data to read or -1 on error. st MUST be zeroed before first call. */
16
  static char partial_hdr[16]; /* a small buffer for storing partial chunk headers, if these are transmitted in separate parts */
16
int unchunk(unsigned char *buff, int bufflen, struct unchunk_state *st) {
17
  int hdrstart, hdrend;
17
  int hdrstart, hdrend;
18
 
18
 
19
  /* if chunk header was being in progress, try to decode it now */
19
  /* if chunk header was being in progress, try to decode it now */
20
  if (bytesleft == -1) {
20
  if (st->bytesleft == -1) {
21
    int partial_hdr_len = strlen(partial_hdr);
21
    int partial_hdr_len = strlen(st->partial_hdr);
22
    /* locate header terminator, if available */
22
    /* locate header terminator, if available */
23
    for (hdrend = 0; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++);
23
    for (hdrend = 0; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++);
24
    if (partial_hdr_len + hdrend > 15) return(-1); /* error: chunk header too long */
24
    if (partial_hdr_len + hdrend > 15) return(-1); /* error: chunk header too long */
25
 
25
 
26
    /* copy header to buffer */
26
    /* copy header to buffer */
27
    memcpy(partial_hdr + partial_hdr_len, buff, hdrend);
27
    memcpy(st->partial_hdr + partial_hdr_len, buff, hdrend);
28
    partial_hdr[partial_hdr_len + hdrend] = 0;
28
    st->partial_hdr[partial_hdr_len + hdrend] = 0;
29
 
29
 
30
    /* quit if header still no complete */
30
    /* quit if header still no complete */
31
    if (hdrend >= bufflen) return(0);
31
    if (hdrend >= bufflen) return(0);
32
 
32
 
33
    /* good, got whole header */
33
    /* good, got whole header */
34
    bufflen -= hdrend + 1;
34
    bufflen -= hdrend + 1;
35
    memmove(buff, buff + hdrend + 1, bufflen);
35
    memmove(buff, buff + hdrend + 1, bufflen);
36
    bytesleft = strtol(partial_hdr, NULL, 16);
36
    st->bytesleft = strtol(st->partial_hdr, NULL, 16);
37
  }
37
  }
38
 
38
 
39
  AGAIN:
39
  AGAIN:
40
 
40
 
41
  if (bufflen <= bytesleft) { /* bufflen <= bytesleft */
41
  if (bufflen <= st->bytesleft) {
42
    bytesleft -= bufflen;
42
    st->bytesleft -= bufflen;
43
    return(bufflen);
43
    return(bufflen);
44
  }
44
  }
45
 
45
 
46
  /* else bufflen > bytesleft */
46
  /* else bufflen > bytesleft */
47
 
47
 
48
  /* skip trailing \r\n after chunk */
48
  /* skip trailing \r\n after chunk */
49
  for (hdrstart = bytesleft; hdrstart < bufflen; hdrstart++) if ((buff[hdrstart] != '\r') && (buff[hdrstart] != '\n')) break;
49
  for (hdrstart = st->bytesleft; hdrstart < bufflen; hdrstart++) if ((buff[hdrstart] != '\r') && (buff[hdrstart] != '\n')) break;
50
  /* skip chunk size (look for its \n terminator) */
50
  /* skip chunk size (look for its \n terminator) */
51
  for (hdrend = hdrstart; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++);
51
  for (hdrend = hdrstart; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++);
52
 
52
 
53
  if (hdrend < bufflen) { /* full header found */
53
  if (hdrend < bufflen) { /* full header found */
54
    long newchunklen;
54
    long newchunklen;
55
    /* read the header length */
55
    /* read the header length */
56
    newchunklen = strtol((char *)buff + hdrstart, NULL, 16);
56
    newchunklen = strtol((char *)buff + hdrstart, NULL, 16);
57
    /* move data over header to get a contiguous block of data */
57
    /* move data over header to get a contiguous block of data */
58
    memmove(buff + bytesleft, buff + hdrend + 1, bufflen - (hdrend + 1));
58
    memmove(buff + st->bytesleft, buff + hdrend + 1, bufflen - (hdrend + 1));
59
    bufflen -= (hdrend + 1 - bytesleft);
59
    bufflen -= (hdrend + 1 - st->bytesleft);
60
    /* update bytesleft */
60
    /* update bytesleft */
61
    bytesleft += newchunklen;
61
    st->bytesleft += newchunklen;
62
    /* loop again */
62
    /* loop again */
63
    goto AGAIN;
63
    goto AGAIN;
64
  } else { /* partial header */
64
  } else { /* partial header */
65
    if ((bufflen - bytesleft) > 15) return(-1); /* error: chunk header appears to be longer than 15 characters */
65
    if ((bufflen - st->bytesleft) > 15) return(-1); /* error: chunk header appears to be longer than 15 characters */
66
    memset(partial_hdr, 0, sizeof(partial_hdr));
66
    memset(st->partial_hdr, 0, sizeof(st->partial_hdr));
67
    memcpy(partial_hdr, buff + bytesleft, bufflen - bytesleft);
67
    memcpy(st->partial_hdr, buff + st->bytesleft, bufflen - st->bytesleft);
68
    bufflen -= (bufflen - bytesleft);
68
    bufflen -= (bufflen - st->bytesleft);
69
    bytesleft = -1; /* "header in progress" */
69
    st->bytesleft = -1; /* "header in progress" */
70
    return(bufflen);
70
    return(bufflen);
71
  }
71
  }
72
}
72
}
73
 
73