hdr->HR.gzip_ok = 1;
}
}
+
+void Header_HandleContentRange(StrBuf *Line, ParsedHttpHdrs *hdr)
+{
+ const char *PRange = ChrPtr(Line);
+
+ while ((*PRange != '=') && (*PRange != '\0'))
+ PRange ++;
+ if (*PRange == '=')
+ PRange ++;
+ if ((*PRange == '\0'))
+ return;
+ hdr->HaveRange = 1;
+ hdr->RangeStart = atol(PRange);
+
+ while (isdigit(*PRange))
+ PRange++;
+
+ if (*PRange == '-')
+ PRange ++;
+ if ((*PRange == '\0'))
+ hdr->RangeTil = -1;
+ else
+ hdr->RangeTil = atol(PRange);
+}
+
const char *ReqStrs[eNONE] = {
"GET",
"POST",
InitModule_CONTEXT
(void)
{
+ RegisterHeaderHandler(HKEY("RANGE"), Header_HandleContentRange);
RegisterHeaderHandler(HKEY("CONTENT-LENGTH"), Header_HandleContentLength);
RegisterHeaderHandler(HKEY("CONTENT-TYPE"), Header_HandleContentType);
RegisterHeaderHandler(HKEY("X-FORWARDED-HOST"), Header_HandleXFFHost); /* Apache way... */
/*
* Send binary data to the client encrypted.
*/
-void client_write_ssl(const StrBuf *Buf)
+int client_write_ssl(const StrBuf *Buf)
{
const char *buf;
int retval;
long nbytes;
char junk[1];
- if (THREADSSL == NULL) return;
+ if (THREADSSL == NULL) return -1;
nbytes = nremain = StrLength(Buf);
buf = ChrPtr(Buf);
syslog(LOG_WARNING, "errno is %d\n", errno);
}
endtls();
- return;
+ return -1;
}
nremain -= retval;
}
+ return 0;
}
StrBufCutLeft(Buf, 4);
bytes = StrBufExtract_long(Buf, 0, '|');
StrBufExtract_token(ContentType, Buf, 3, '|');
- serv_read_binary(WCC->WBuf, bytes, Buf);
- serv_puts("CLOS");
- StrBuf_ServGetln(Buf);
+
CheckGZipCompressionAllowed (SKEY(ContentType));
if (force_download)
FlushStrBuf(ContentType);
- http_transmit_thing(ChrPtr(ContentType), 0);
+
+ serv_read_binary_to_http(ContentType, bytes, 0, 0);
+ serv_puts("CLOS");
+ StrBuf_ServGetln(Buf);
+// http_transmit_thing(ChrPtr(ContentType), 0);
} else {
StrBufCutLeft(Buf, 4);
hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
}
+int client_write(StrBuf *ThisBuf)
+{
+ wcsession *WCC = WC;
+ const char *ptr, *eptr;
+ long count;
+ ssize_t res = 0;
+ fd_set wset;
+ int fdflags;
+
+ ptr = ChrPtr(ThisBuf);
+ count = StrLength(ThisBuf);
+ eptr = ptr + count;
+
+ fdflags = fcntl(WC->Hdr->http_sock, F_GETFL);
+
+ while ((ptr < eptr) && (WCC->Hdr->http_sock != -1)) {
+ if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
+ FD_ZERO(&wset);
+ FD_SET(WCC->Hdr->http_sock, &wset);
+ if (select(WCC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
+ syslog(LOG_INFO, "client_write: Socket select failed (%s)\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ if ((WCC->Hdr->http_sock == -1) ||
+ (res = write(WCC->Hdr->http_sock,
+ ptr,
+ count)) == -1) {
+ syslog(LOG_INFO, "client_write: Socket write failed (%s)\n", strerror(errno));
+ wc_backtrace(LOG_INFO);
+ return res;
+ }
+ count -= res;
+ ptr += res;
+ }
+ return 0;
+}
+
+/*
+ * Read binary data from server into memory using a series of server READ commands.
+ * returns the read content as StrBuf
+ */
+void serv_read_binary_to_http(StrBuf *MimeType, size_t total_len, int is_static, int detect_mime)
+{
+ wcsession *WCC = WC;
+ size_t bytes_read = 0;
+ size_t this_block = 0;
+ int rc = 6;
+ int ServerRc = 6;
+ int first = 1;
+ int chunked = 0;
+ StrBuf *BufHeader;
+ StrBuf *Buf;
+
+
+ if (WCC->Hdr->HaveRange)
+ {
+ WCC->Hdr->HaveRange++;
+ WCC->Hdr->TotalBytes = total_len;
+ /* open range? or beyound file border? correct the numbers. */
+ if ((WCC->Hdr->RangeTil == -1) || (WCC->Hdr->RangeTil>= total_len))
+ WCC->Hdr->RangeTil = total_len - 1;
+ bytes_read = WCC->Hdr->RangeStart;
+ total_len = WCC->Hdr->RangeTil;
+ }
+ else
+ chunked = total_len > SIZ * 10; /* TODO: disallow for HTTP / 1.0 */
+
+ if (chunked)
+ {
+ BufHeader=NewStrBuf();
+ }
+ Buf = NewStrBuf();
+
+ http_transmit_headers(ChrPtr(MimeType), is_static, chunked);
+#ifdef HAVE_OPENSSL
+ if (is_https)
+ client_write_ssl(WCC->HBuf);
+ else
+#endif
+ client_write(WCC->HBuf);
+
+ while ((bytes_read < total_len) && (ServerRc == 6)) {
+
+ if (WCC->serv_sock==-1) {
+ FlushStrBuf(WCC->WBuf);
+ return;
+ }
+
+ serv_printf("READ "SIZE_T_FMT"|"SIZE_T_FMT, bytes_read, total_len-bytes_read);
+ if ( (rc = StrBuf_ServGetln(Buf) > 0) &&
+ (ServerRc = GetServerStatus(Buf, NULL), ServerRc == 6) )
+ {
+ if (rc < 0)
+ return;
+ StrBufCutLeft(Buf, 4);
+ this_block = StrTol(Buf);
+ rc = StrBuf_ServGetBLOBBuffered(WCC->WBuf, this_block);
+ if (rc < 0) {
+ syslog(LOG_INFO, "Server connection broken during download\n");
+ wc_backtrace(LOG_INFO);
+ if (WCC->serv_sock > 0) close(WCC->serv_sock);
+ WCC->serv_sock = (-1);
+ WCC->connected = 0;
+ WCC->logged_in = 0;
+ return;
+ }
+ bytes_read += rc;
+
+ }
+
+ if (chunked)
+ {
+ StrBufPrintf(BufHeader, "%s%x\r\n",
+ (first)?"":"\r\n",
+ StrLength (WCC->WBuf));
+#ifdef HAVE_OPENSSL
+ if (is_https)
+ rc = client_write_ssl(BufHeader);
+ else
+#endif
+ rc = client_write(BufHeader);
+ if (rc < 0)
+ break;
+ }
+
+#ifdef HAVE_OPENSSL
+ if (is_https)
+ rc = client_write_ssl(WCC->WBuf);
+ else
+#endif
+ rc = client_write(WCC->WBuf);
+
+ if (rc < 0)
+ break;
+ first = 0;
+ FlushStrBuf(WCC->WBuf);
+ }
+
+ if (chunked)
+ {
+ StrBufPrintf(BufHeader, "\r\n0\r\n\r\n");
+#ifdef HAVE_OPENSSL
+ if (is_https)
+ rc = client_write_ssl(BufHeader);
+ else
+#endif
+ rc = client_write(BufHeader);
+ }
+
+}
+
int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target)
{
const char *Error;
int serv_putbuf(const StrBuf *string);
int serv_printf(const char *format,...)__attribute__((__format__(__printf__,1,2)));
int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf);
+void serv_read_binary_to_http(StrBuf *MimeType, size_t total_len, int is_static, int detect_mime);
int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize);
int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize);
int read_server_text(StrBuf *Buf, long *nLines);
wcsession *WCC = WC;
char httpnow[128];
- hprintf("HTTP/1.1 200 OK\n");
+ if (WCC->Hdr->HaveRange > 1)
+ hprintf("HTTP/1.1 206 Partial Content\r\n");
+ else
+ hprintf("HTTP/1.1 200 OK\r\n");
+
http_datestring(httpnow, sizeof httpnow, time(NULL));
if (do_httpheaders) {
end_burst();
}
+void http_transmit_headers(const char *content_type, int is_static, long is_chunked)
+{
+ wcsession *WCC = WC;
+ syslog(LOG_DEBUG, "http_transmit_thing(%s)%s", content_type, ((is_static > 0) ? " (static)" : ""));
+ output_headers(0, 0, 0, 0, 0, is_static);
+
+ if (WCC->Hdr->HaveRange)
+ hprintf("Accept-Ranges: bytes\r\n"
+ "Content-Range: bytes %ld-%ld/%ld\r\n",
+ WCC->Hdr->RangeStart,
+ WCC->Hdr->RangeTil,
+ WCC->Hdr->TotalBytes);
+
+ hprintf("Content-type: %s\r\n"
+ "Server: "PACKAGE_STRING"\r\n"
+ "%s"
+ "Connection: close\r\n\r\n",
+ content_type,
+ (is_chunked)?"Transfer-Encoding: chunked\r\n":"");
+}
+
/*
* Convenience functions to display a page containing only a string
typedef struct _ParsedHttpHdrs {
int http_sock; /* HTTP server socket */
+ long HaveRange;
+ long RangeStart;
+ long RangeTil;
+ long TotalBytes;
const char *Pos;
StrBuf *ReadBuf;
int starttls(int sock);
extern SSL_CTX *ssl_ctx;
int client_read_sslbuffer(StrBuf *buf, int timeout);
-void client_write_ssl(const StrBuf *Buf);
+int client_write_ssl(const StrBuf *Buf);
#endif
extern int is_https;
long locate_user_vcard_in_this_room(message_summary **VCMsg,
wc_mime_attachment **VCAtt);
void http_transmit_thing(const char *content_type, int is_static);
+void http_transmit_headers(const char *content_type, int is_static, long is_chunked);
long unescape_input(char *buf);
void check_thread_pool_size(void);
void StrEndTab(StrBuf *Target, int tabnum, int num_tabs);