+/*
+ * 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)
+{
+ int ServerRc = 6;
+ wcsession *WCC = WC;
+ size_t bytes_read = 0;
+ int first = 1;
+ int client_con_state = 0;
+ int chunked = 0;
+ int is_gzip = 0;
+ const char *Err = NULL;
+ StrBuf *BufHeader = NULL;
+ StrBuf *Buf;
+ StrBuf *pBuf = NULL;
+ vStreamT *SC = NULL;
+ IOBuffer ReadBuffer;
+ IOBuffer WriteBuffer;
+
+
+ Buf = NewStrBuf();
+
+ 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();
+ }
+
+ if ((detect_mime != 0) && (bytes_read != 0))
+ {
+ /* need to read first chunk to detect mime, though the client doesn't care */
+ size_t bytes_read = 0;
+ const char *CT;
+
+ ServerRc = read_serv_chunk(
+ Buf,
+ total_len,
+ &bytes_read);
+
+ if (ServerRc != 6)
+ {
+ FreeStrBuf(&BufHeader);
+ FreeStrBuf(&Buf);
+ return;
+ }
+ CT = GuessMimeType(SKEY(WCC->WBuf));
+ FlushStrBuf(WCC->WBuf);
+ StrBufPlain(MimeType, CT, -1);
+ CheckGZipCompressionAllowed(SKEY(MimeType));
+ detect_mime = 0;
+ FreeStrBuf(&Buf);
+ }
+
+ memset(&WriteBuffer, 0, sizeof(IOBuffer));
+ if (chunked && !DisableGzip && WCC->Hdr->HR.gzip_ok)
+ {
+ is_gzip = 1;
+ SC = StrBufNewStreamContext (eZLibEncode, &Err);
+ if (SC == NULL) {
+ syslog(LOG_ERR, "Error while initializing stream context: %s", Err);
+ FreeStrBuf(&Buf);
+ return;
+ }
+
+ memset(&ReadBuffer, 0, sizeof(IOBuffer));
+ ReadBuffer.Buf = WCC->WBuf;
+
+ WriteBuffer.Buf = NewStrBufPlain(NULL, SIZ*2);;
+ pBuf = WriteBuffer.Buf;
+ }
+ else
+ {
+ pBuf = WCC->WBuf;
+ }
+
+ if (!detect_mime)
+ {
+ http_transmit_headers(ChrPtr(MimeType), is_static, chunked, is_gzip);
+
+ if (send_http(WCC->HBuf) < 0)
+ {
+ FreeStrBuf(&Buf);
+ FreeStrBuf(&WriteBuffer.Buf);
+ FreeStrBuf(&BufHeader);
+ if (StrBufDestroyStreamContext(eZLibEncode, &SC, &Err) && Err) {
+ syslog(LOG_ERR, "Error while destroying stream context: %s", Err);
+ }
+ return;
+ }
+ }
+
+ while ((bytes_read < total_len) &&
+ (ServerRc == 6) &&
+ (client_con_state == 0))
+ {
+
+ if (WCC->serv_sock==-1) {
+ FlushStrBuf(WCC->WBuf);
+ FreeStrBuf(&Buf);
+ FreeStrBuf(&WriteBuffer.Buf);
+ FreeStrBuf(&BufHeader);
+ StrBufDestroyStreamContext(eZLibEncode, &SC, &Err);
+ if (StrBufDestroyStreamContext(eZLibEncode, &SC, &Err) && Err) {
+ syslog(LOG_ERR, "Error while destroying stream context: %s", Err);
+ }
+ return;
+ }
+
+ ServerRc = read_serv_chunk(
+ Buf,
+ total_len,
+ &bytes_read);
+ if (ServerRc != 6)
+ break;
+
+ if (detect_mime)
+ {
+ const char *CT;
+ detect_mime = 0;
+
+ CT = GuessMimeType(SKEY(WCC->WBuf));
+ StrBufPlain(MimeType, CT, -1);
+ if (is_gzip) {
+ CheckGZipCompressionAllowed(SKEY(MimeType));
+ is_gzip = WCC->Hdr->HR.gzip_ok;
+ }
+ http_transmit_headers(ChrPtr(MimeType), is_static, chunked, is_gzip);
+
+ client_con_state = send_http(WCC->HBuf);
+ }
+
+ if (is_gzip)
+ {
+ int done = (bytes_read == total_len);
+ while ((IOBufferStrLength(&ReadBuffer) > 0) && (client_con_state == 0)) {
+ int rc;
+
+ do {
+ rc = StrBufStreamTranscode(eZLibEncode, &WriteBuffer, &ReadBuffer, NULL, -1, SC, done, &Err);
+
+ if (StrLength (pBuf) > 0) {
+ StrBufPrintf(BufHeader, "%s%x\r\n",
+ (first)?"":"\r\n",
+ StrLength (pBuf));
+ first = 0;
+ client_con_state = send_http(BufHeader);
+ if (client_con_state == 0) {
+ client_con_state = send_http(pBuf);
+ }
+ FlushStrBuf(pBuf);
+ }
+ } while ((rc == 1) && (StrLength(pBuf) > 0));
+ }
+ FlushStrBuf(WCC->WBuf);
+ }
+ else {
+ if ((chunked) && (client_con_state == 0))
+ {
+ StrBufPrintf(BufHeader, "%s%x\r\n",
+ (first)?"":"\r\n",
+ StrLength (pBuf));
+ first = 0;
+ client_con_state = send_http(BufHeader);
+ }