diff --git a/bin/webs.c b/bin/webs.c
index b5a30c0..9776b13 100644
--- a/bin/webs.c
+++ b/bin/webs.c
@@ -27,8 +27,16 @@ struct htts_ext_t
};
typedef struct htts_ext_t htts_ext_t;
+struct buff_t
+{
+ hio_uint8_t buf[4096];
+ hio_oow_t len;
+};
+typedef struct buff_t buff_t;
-void untar (hio_t* hio, hio_dev_thr_iopair_t* iop, hio_svc_htts_thr_func_info_t* tfi, void* ctx)
+/* ------------------------------------------------------------------------- */
+
+static void untar (hio_t* hio, hio_dev_thr_iopair_t* iop, hio_svc_htts_thr_func_info_t* tfi, void* ctx)
{
FILE* wfp = HIO_NULL;
htts_ext_t* ext;
@@ -82,6 +90,70 @@ done:
}
}
+/* ------------------------------------------------------------------------- */
+
+static hio_oow_t write_all_to_fd (int fd, const hio_uint8_t* ptr, hio_oow_t len)
+{
+ hio_oow_t rem = len;
+
+ while (rem > 0)
+ {
+ hio_ooi_t n;
+ n = write(fd, ptr, rem);
+ if (n <= -1) break;
+ rem -= n;
+ ptr += n;
+ }
+
+ return len - rem; /* return the number of bytes written */
+}
+
+static HIO_INLINE void init_buff (buff_t* buf)
+{
+ buf->len = 0;
+}
+
+static int flush_buff_to_fd (int fd, buff_t* buf)
+{
+ if (buf->len > 0)
+ {
+ hio_oow_t n;
+ n = write_all_to_fd(fd, buf->buf, buf->len);
+ buf->len -= n;
+ if (buf->len > 0) return -1;
+ }
+ return 0;
+}
+
+static int write_buff_to_fd (int fd, buff_t* buf, const void* ptr, hio_oow_t len)
+{
+ hio_oow_t rcapa;
+
+ rcapa = HIO_COUNTOF(buf->buf) - buf->len;
+ if (len >= HIO_COUNTOF(buf->buf) + rcapa)
+ {
+ if (flush_buff_to_fd(fd, buf) <= -1) return -1;
+ if (write_all_to_fd(fd, (const hio_uint8_t*)ptr, len) != len) return -1;
+ }
+ else if (len >= rcapa)
+ {
+ HIO_MEMCPY (&buf->buf[buf->len], ptr, rcapa);
+ buf->len += rcapa;
+ if (flush_buff_to_fd(fd, buf) <= -1) return -1;
+ HIO_MEMCPY (buf->buf, (const hio_uint8_t*)ptr + rcapa, len - rcapa);
+ buf->len = len - rcapa;
+ }
+ else
+ {
+ HIO_MEMCPY (&buf->buf[buf->len], ptr, len);
+ buf->len += len;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
static const hio_bch_t* file_get_mime_type (hio_svc_htts_t* htts, const hio_bch_t* qpath, const hio_bch_t* file_path, void* ctx)
{
const hio_bch_t* mt = HIO_NULL;
@@ -99,6 +171,7 @@ static int file_open_dir_list (hio_svc_htts_t* htts, const hio_bch_t* qpath, con
hio_bch_t file_path[] = "/tmp/.XXXXXX";
int fd = -1;
struct dirent* de;
+ buff_t buf;
if (ext->ai->file_load_index_page)
{
@@ -134,42 +207,66 @@ static int file_open_dir_list (hio_svc_htts_t* htts, const hio_bch_t* qpath, con
unlink (file_path);
- write (fd, "
", 12);
- if (!(qpath[0] == '\0' || (qpath[0] == '/' && qpath[1] == '\0')))
- write (fd, "..", 23);
+ buf.len = 0;
+ init_buff (&buf);
+
+ if (write_buff_to_fd(fd, &buf, "", 12) <= -1) goto oops;
+ if (!(qpath[0] == '\0' || (qpath[0] == '/' && qpath[1] == '\0')) &&
+ write_buff_to_fd(fd, &buf,"..", 23) <= -1) goto oops;
-/* TODO: sorting, other informatino like size, */
-/* TODO: error handling of write() error */
while ((de = readdir(dp)))
{
struct stat st;
- hio_bch_t* tmp_path;
+ hio_bch_t* tptr, * dend;
+ hio_bch_t tmp[1024]; /* this must be at least 5 characters large for html escaping */
+ hio_oow_t tml;
int n;
if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
(de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) continue;
- tmp_path = hio_svc_htts_dupmergepaths(htts, dir_path, de->d_name);
- if (HIO_UNLIKELY(!tmp_path)) continue;
- n = stat(tmp_path, &st);
- hio_freemem (hio, tmp_path);
+ tptr = hio_svc_htts_dupmergepaths(htts, dir_path, de->d_name);
+ if (HIO_UNLIKELY(!tptr)) continue;
+ n = stat(tptr, &st);
+ hio_freemem (hio, tptr);
if (HIO_UNLIKELY(n <= -1)) continue;
- write (fd, "d_name + strlen(de->d_name);
+
+ if (write_buff_to_fd(fd, &buf, "d_name; tptr < dend; )
{
- char tmp[1000]; /* TODO:use dynamic buffer?? */
- hio_perenc_http_bcstr(0, de->d_name, tmp, HIO_NULL); /* url encoding */
- //write (fd, de->d_name, strlen(de->d_name));
- write (fd, tmp, strlen(tmp));
+ hio_oow_t dlen = dend - tptr;
+ if (dlen > HIO_COUNTOF(tmp) / 3) dlen = HIO_COUNTOF(tmp) / 3; /* it can grow upto 3 folds */
+ HIO_ASSERT (hio, dlen >= 1);
+ tml = hio_perenc_http_bchars(tptr, dlen, tmp, HIO_COUNTOF(tmp), 0); /* feed a chunk that won't overflow the buffer */
+ HIO_ASSERT (hio, tml <= HIO_COUNTOF(tmp)); /* the buffer 'tmp' must be large enough */
+ if (write_buff_to_fd(fd, &buf, tmp, tml) <= -1) goto oops;
+ tptr += dlen;
}
- if (S_ISDIR(st.st_mode)) write (fd, "/", 1);
- write (fd, "\">", 2);
- write (fd, de->d_name, strlen(de->d_name)); /* TODO: html entity encoding */
- if (S_ISDIR(st.st_mode)) write (fd, "/", 1);
- write (fd, "", 4);
+
+ if (S_ISDIR(st.st_mode) && write_buff_to_fd(fd, &buf, "/", 1) <= -1) goto oops;
+ if (write_buff_to_fd(fd, &buf, "\">", 2) <= -1) goto oops;
+
+ dend = de->d_name + strlen(de->d_name);
+ for (tptr = de->d_name; tptr < dend; )
+ {
+ hio_oow_t dlen = dend - tptr;
+ if (dlen > HIO_COUNTOF(tmp) / 5) dlen = HIO_COUNTOF(tmp) / 5; /* it can grow upto 5 folds */
+ HIO_ASSERT (hio, dlen >= 1);
+ tml = hio_escape_html_bchars(tptr, dlen, tmp, HIO_COUNTOF(tmp)); /* feed a chunk that won't overflow the buffer */
+ HIO_ASSERT (hio, tml <= HIO_COUNTOF(tmp)); /* the buffer 'tmp' must be large enough */
+ if (write_buff_to_fd(fd, &buf, tmp, tml) <= -1) goto oops;
+ tptr += dlen;
+ }
+
+ if (S_ISDIR(st.st_mode) && write_buff_to_fd(fd, &buf, "/", 1) <= -1) goto oops;
+ if (write_buff_to_fd(fd, &buf, "", 4) <= -1) goto oops;
}
- write (fd, "\n", 15);
+ if (write_buff_to_fd(fd, &buf, "\n", 15) <= -1) goto oops;
+ if (flush_buff_to_fd(fd, &buf) <= -1) goto oops;
closedir (dp);
lseek (fd, SEEK_SET, 0);
diff --git a/lib/hio-http.h b/lib/hio-http.h
index 4cf8f04..45f9ca4 100644
--- a/lib/hio-http.h
+++ b/lib/hio-http.h
@@ -257,26 +257,32 @@ HIO_EXPORT hio_oow_t hio_perdec_http_bcs (
/**
* The hio_perenc_http_bcstr() function performs percent-encoding over a string.
- * The caller must ensure that the output buffer \a buf is large enough.
- * If \a nencs is not #HIO_NULL, it is set to the number of characters
- * encoded. 0 means no characters in the input string required encoding.
- * \return the length of the output string.
+ * It returns the length of the encoded string if \a len is long enough to hold
+ * the resulting string and the terminating null. If the return value is equal to
+ * or greater than \a len, the buffer pointed to by \a buf of the length \a len
+ * is not large enough.
+ * \return the length of the output string encoded on success or the number of encoded
+ * string that would have been written if the buffer has been large enough.
*/
HIO_EXPORT hio_oow_t hio_perenc_http_bcstr (
- int opt, /**< 0 or bitwise-OR'ed of #hio_perenc_http_bcstr_opt_t */
const hio_bch_t* str,
hio_bch_t* buf,
- hio_oow_t* nencs
+ hio_oow_t len,
+ int opt /**< 0 or bitwise-OR'ed of #hio_perenc_http_bcstr_opt_t */
);
-#if 0
-/* TODO: rename this function according to the naming convension */
-HIO_EXPORT hio_bch_t* hio_perenc_http_bcstrdup (
- int opt, /**< 0 or bitwise-OR'ed of #hio_perenc_http_bcstr_opt_t */
- const hio_bch_t* str,
- hio_mmgr_t* mmgr
+/**
+ * The hio_perenc_http_bchars() function performs percent-ending over a length-bound string.
+ * It doesn't null-terminate the result. The buffer requirement is less than hio_perenc_http_bcstr()
+ * by 1.
+ */
+HIO_EXPORT hio_oow_t hio_perenc_http_bchars (
+ const hio_bch_t* str,
+ hio_oow_t sln,
+ hio_bch_t* buf,
+ hio_oow_t len,
+ int opt /**< 0 or bitwise-OR'ed of #hio_perenc_http_bcstr_opt_t */
);
-#endif
HIO_EXPORT int hio_scan_http_qparam (
hio_bch_t* qparam,
@@ -284,6 +290,18 @@ HIO_EXPORT int hio_scan_http_qparam (
void* ctx
);
+HIO_EXPORT hio_oow_t hio_escape_html_bchars (
+ const hio_bch_t* str,
+ hio_oow_t sln,
+ hio_bch_t* buf,
+ hio_oow_t len
+);
+
+HIO_EXPORT hio_oow_t hio_escape_html_bcstr (
+ const hio_bch_t* str,
+ hio_bch_t* buf,
+ hio_oow_t len
+);
/* ------------------------------------------------------------------------- */
/* HTTP SERVER SERVICE */
/* ------------------------------------------------------------------------- */
diff --git a/lib/http.c b/lib/http.c
index d0a969a..abef080 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -499,87 +499,73 @@ hio_oow_t hio_perdec_http_bcs (const hio_bcs_t* str, hio_bch_t* buf, hio_oow_t*
#define TO_HEX(v) ("0123456789ABCDEF"[(v) & 15])
-hio_oow_t hio_perenc_http_bcstr (int opt, const hio_bch_t* str, hio_bch_t* buf, hio_oow_t* nencs)
+hio_oow_t hio_perenc_http_bchars (const hio_bch_t* str, hio_oow_t sln, hio_bch_t* buf, hio_oow_t len, int opt)
{
- const hio_bch_t* p = str;
+ const hio_bch_t* ptr, * end = str + sln;
hio_bch_t* out = buf;
- hio_oow_t enc_count = 0;
+ hio_bch_t slash;
+ hio_oow_t reqlen = 0;
- /* this function doesn't accept the size of the buffer. the caller must
- * ensure that the buffer is large enough */
+ slash = (opt & HIO_PERENC_HTTP_KEEP_SLASH)? '/': '\0';
- if (opt & HIO_PERENC_HTTP_KEEP_SLASH)
+ for (ptr = str; ptr < end; ptr++)
{
- while (*p != '\0')
+ reqlen += (IS_UNRESERVED(*ptr) || *ptr == slash)? 1: 3;
+ }
+
+ if (len >= reqlen)
+ {
+ ptr = str;
+ while (ptr < end)
{
- if (IS_UNRESERVED(*p) || *p == '/') *out++ = *p;
+ if (IS_UNRESERVED(*ptr) || *ptr == slash) *out++ = *ptr;
else
{
*out++ = '%';
- *out++ = TO_HEX (*p >> 4);
- *out++ = TO_HEX (*p & 15);
- enc_count++;
+ *out++ = TO_HEX(*ptr >> 4);
+ *out++ = TO_HEX(*ptr & 15);
}
- p++;
+ ptr++;
}
}
- else
- {
- while (*p != '\0')
- {
- if (IS_UNRESERVED(*p)) *out++ = *p;
- else
- {
- *out++ = '%';
- *out++ = TO_HEX (*p >> 4);
- *out++ = TO_HEX (*p & 15);
- enc_count++;
- }
- p++;
- }
- }
- *out = '\0';
- if (nencs) *nencs = enc_count;
- return out - buf;
+
+ return reqlen;
}
-#if 0
-hio_bch_t* hio_perenc_http_bcstrdup (int opt, const hio_bch_t* str, hio_mmgr_t* mmgr)
+hio_oow_t hio_perenc_http_bcstr (const hio_bch_t* str, hio_bch_t* buf, hio_oow_t len, int opt)
{
- hio_bch_t* buf;
- hio_oow_t len = 0;
- hio_oow_t count = 0;
-
- /* count the number of characters that should be encoded */
- if (opt & HIO_PERENC_HTTP_KEEP_SLASH)
+ const hio_bch_t* ptr = str;
+ hio_bch_t* out = buf;
+ hio_bch_t slash;
+ hio_oow_t reqlen = 0;
+
+ slash = (opt & HIO_PERENC_HTTP_KEEP_SLASH)? '/': '\0';
+
+ for (ptr = str; *ptr != '\0'; ptr++)
{
- for (len = 0; str[len] != '\0'; len++)
- {
- if (!IS_UNRESERVED(str[len]) && str[len] != '/') count++;
- }
- }
- else
- {
- for (len = 0; str[len] != '\0'; len++)
- {
- if (!IS_UNRESERVED(str[len])) count++;
- }
+ reqlen += (IS_UNRESERVED(*ptr) || *ptr == slash)? 1: 3;
}
- /* if there are no characters to escape, just return the original string */
- if (count <= 0) return (hio_bch_t*)str;
+ if (len > reqlen)
+ {
+ ptr = str;
+ while (*ptr != '\0')
+ {
+ if (IS_UNRESERVED(*ptr) || *ptr == slash) *out++ = *ptr;
+ else
+ {
+ *out++ = '%';
+ *out++ = TO_HEX(*ptr >> 4);
+ *out++ = TO_HEX(*ptr & 15);
+ }
+ ptr++;
+ }
- /* allocate a buffer of an optimal size for escaping, otherwise */
- buf = HIO_MMGR_ALLOC(mmgr, (len + (count * 2) + 1) * HIO_SIZEOF(*buf));
- if (!buf) return HIO_NULL;
+ *out = '\0';
+ }
- /* perform actual escaping */
- hio_perenc_http_bcstr (opt, str, buf, HIO_NULL);
-
- return buf;
+ return reqlen;
}
-#endif
-
int hio_scan_http_qparam (hio_bch_t* qparam, int (*qparamcb) (hio_bcs_t* key, hio_bcs_t* val, void* ctx), void* ctx)
{
@@ -638,3 +624,116 @@ int hio_scan_http_qparam (hio_bch_t* qparam, int (*qparamcb) (hio_bcs_t* key, hi
return 0;
}
+
+hio_oow_t hio_escape_html_bchars (const hio_bch_t* str, hio_oow_t sln, hio_bch_t* buf, hio_oow_t len)
+{
+ hio_bch_t* ptr, * end = str + sln;
+ hio_oow_t reqlen = 0;
+
+ for (ptr = (hio_bch_t*)str; ptr < end; ptr++)
+ {
+ switch (*ptr)
+ {
+ case '<':
+ case '>':
+ reqlen += 4;
+ break;
+
+ case '&':
+ reqlen += 5;
+ break;
+
+ default:
+ reqlen++;
+ break;
+ }
+ }
+
+ if (len >= reqlen)
+ {
+ /* the buffer is large enough */
+ ptr = buf;
+ while (str < end)
+ {
+ switch (*str)
+ {
+ case '<':
+ *ptr++ = '&'; *ptr++ = 'l'; *ptr++ = 't'; *ptr++ = ';';
+ break;
+
+ case '>':
+ *ptr++ = '&'; *ptr++ = 'g'; *ptr++ = 't'; *ptr++ = ';';
+ break;
+
+ case '&':
+ *ptr++ = '&'; *ptr++ = 'a'; *ptr++ = 'm'; *ptr++ = 'p'; *ptr++ = ';';
+ break;
+
+ default:
+ *ptr++ = *str;
+ break;
+ }
+ str++;
+ }
+ }
+
+ /* NOTE no null termination */
+ return reqlen;
+}
+
+hio_oow_t hio_escape_html_bcstr (const hio_bch_t* str, hio_bch_t* buf, hio_oow_t len)
+{
+ hio_bch_t* ptr;
+ hio_oow_t reqlen = 0;
+
+ for (ptr = (hio_bch_t*)str; *ptr != '\0'; ptr++)
+ {
+ switch (*ptr)
+ {
+ case '<':
+ case '>':
+ reqlen += 4;
+ break;
+
+ case '&':
+ reqlen += 5;
+ break;
+
+ default:
+ reqlen++;
+ break;
+ }
+ }
+
+ if (len > reqlen)
+ {
+ /* the buffer is large enough */
+ ptr = buf;
+ while (*str != '\0')
+ {
+ switch (*str)
+ {
+ case '<':
+ *ptr++ = '&'; *ptr++ = 'l'; *ptr++ = 't'; *ptr++ = ';';
+ break;
+
+ case '>':
+ *ptr++ = '&'; *ptr++ = 'g'; *ptr++ = 't'; *ptr++ = ';';
+ break;
+
+ case '&':
+ *ptr++ = '&'; *ptr++ = 'a'; *ptr++ = 'm'; *ptr++ = 'p'; *ptr++ = ';';
+ break;
+
+ default:
+ *ptr++ = *str;
+ break;
+ }
+ str++;
+ }
+
+ *ptr = '\0';
+ }
+
+ return reqlen;
+}