Rectangle 27 2

# Copyright (C) 2008 Brian Candler, released under Ruby Licence.
#
# A collection of small monkey-patches to webrick.

require 'webrick'

module WEBrick

  class HTTPRequest
    # Generate HTTP/1.1 100 continue response. See
    # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/18459
    def continue
      if self['expect'] == '100-continue' && @config[:HTTPVersion] >= "1.1"
        @socket.write "HTTP/#{@config[:HTTPVersion]} 100 continue\r\n\r\n"
        @header.delete('expect')
      end
    end
  end

  class HTTPResponse
    alias :orig_setup_header :setup_header
    # Correct termination of streamed HTTP/1.1 responses. See
    # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/18454 and
    # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/18565
    def setup_header
      orig_setup_header
      unless chunked? || @header['content-length']
        @header['connection'] = "close"
        @keep_alive = false
      end
    end

    # Allow streaming of zipfile entry. See
    # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/18460
    def send_body(socket)
      if @body.respond_to?(:read) then send_body_io(socket)
      elsif @body.respond_to?(:call) then send_body_proc(socket)
      else send_body_string(socket)
      end
    end

    # If the response body is a proc, then we invoke it and pass in
    # an object which supports "write" and "<<" methods. This allows
    # arbitary output streaming.
    def send_body_proc(socket)
      if @request_method == "HEAD"
        # do nothing
      elsif chunked?
        @body.call(ChunkedWrapper.new(socket, self))
        _write_data(socket, "0#{CRLF}#{CRLF}")
      else
        size = @header['content-length'].to_i
        @body.call(socket)   # TODO: StreamWrapper which supports offset, size
        @sent_size = size
      end
    end

    class ChunkedWrapper
      def initialize(socket, resp)
        @socket = socket
        @resp = resp
      end
      def write(buf)
        return if buf.empty?
        data = ""
        data << format("%x", buf.size) << CRLF
        data << buf << CRLF
        socket = @socket
        @resp.instance_eval {
          _write_data(socket, data)
          @sent_size += buf.size
        }
      end
      alias :<< :write
    end
  end
end

if RUBY_VERSION < "1.9"
  old_verbose, $VERBOSE = $VERBOSE, nil
  # Increase from default of 4K for efficiency, similar to
  # http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/net/protocol.rb?r1=11708&r2=12092
  # In trunk the default is 64K and can be adjusted using :InputBufferSize,
  # :OutputBufferSize
  WEBrick::HTTPRequest::BUFSIZE = 16384
  WEBrick::HTTPResponse::BUFSIZE = 16384
  $VERBOSE = old_verbose
end

to use simply pass a proc to as the response body, like so

res.body = proc { |w|
  10.times do
    w << Time.now.to_s
    sleep(1)
  end
}

ruby - streaming html from webrick? - Stack Overflow

ruby streaming webrick
Rectangle 27 0

Here's a snippet of code (that works) that the client can use to read from the zipped stream:

static void processZippedInputStream(InputStream in, String entryNameRegex)
throws IOException
{
    ZipInputStream zin = new ZipInputStream(in);
    ZipEntry ze;
    while ((ze = zin.getNextEntry()) != null)
    {
        if (ze.getName().matches(entryNameRegex))
        {
            // treat zin as a normal input stream - ie read() from it till "empty" etc
            break;
        }
        zin.closeEntry();
    }
    zin.close();
}

The main difference with a normal InputStream is iterating through the entries. You may know, for example, that you want the first entry, so no need for the name matching parameter etc.

as i said, the zipfile would only contain one single entry. unforutnately it seems that the metainformation about this is at the very end of the zipfile, so i would need to download the whole file before i can start to unzip, right?

No - the entries are encountered by name then contents, so you'll get the entry header right up front

Java: Stream Contents of Zipfile via HTTP - Stack Overflow

java http streaming zip
Rectangle 27 0

Yes you can, Stream the zip and use the MIME type as application/zip

If you actually want to play stream music on the other end, then it can't be done trivially as you can only unpack once the entire zip is available on client.

If size is you concern, you can either turn down your mp3 bit-rate or use formats such as ogg/vorbis

@clamp: You can stream it, but you can't unpack it until you receive the entire contents of the file on the client side. (that's what the image/article is describing)

well ok, but this is actually what i want. the contents of the file is what i want to stream.

Java: Stream Contents of Zipfile via HTTP - Stack Overflow

java http streaming zip
Rectangle 27 0

using Ionic.Zip; // from NUGET-Package "DotNetZip"

public HttpResponseMessage Zipped()
{
    using (var zipFile = new ZipFile())
    {
        // add all files you need from disk, database or memory
        // zipFile.AddEntry(...);

        return ZipContentResult(zipFile);
    }
}

protected HttpResponseMessage ZipContentResult(ZipFile zipFile)
{
    // inspired from http://stackoverflow.com/a/16171977/92756
    var pushStreamContent = new PushStreamContent((stream, content, context) =>
    {
        zipFile.Save(stream);
        stream.Close(); // After save we close the stream to signal that we are done writing.
    }, "application/zip");

    return new HttpResponseMessage(HttpStatusCode.OK) {Content = pushStreamContent};
}

The ZipContentResult method could also live in a base class and be used from any other action in any api controller.

that works great. Don't know why this went unnoticed

c# - Using ASP.NET Web API, how can a controller return a collection o...

c# .net asp.net-web-api dotnetzip
Rectangle 27 0

Would it make more sense to let the web server do the zipping? If you are simply trying to reduce the amount of bandwidth being used, rather than really wanting to store the file zipped up on the server, this would simply be a matter of configurations, for example see:

for HTTP/1.1 GZIP compression. The server can force the response to the client to be zipped.

The client will receive zipped packets and handle the unzipping. It should be possible to stream the file too, so the client doesn't need all the file before it can do something useful, because the server can zip individual chunks.

I agree with @Ant's basic point--if you've got a single file, use straight compression rather than a zip archive. The file can be compressed or not on the server, as you like.

you have not got the problem here. If you zip the file, then to unzip at the other end, you need the entire zip file. So you can't make any use of the data inside the zip if its partially there on the client. So basically even though the zip file itself is getting streamed, the audio itself is not. I believe the solution is to use low-bit rate or better streaming formats

@Suraj if the individual chunks are zipped, then no, you dont have the problem. but its true that you need to check what happens if you used Transfer-Encoding chunked together with GZIP compression. potentially, you need to use just chunked transfer encoding, and zip the chunks yourself and unzip them on the client, which is messy! i dont really know exactly how it works without trying it, but i assume individual chunks will be gzipped. if anyone tries it, let me know!

en.wikipedia.org/wiki/Gzip - seems to suggest gzip uses a stream, ie you dont need the entire thing to start unzipping... so i imagine it works. try it and see :-)

Java: Stream Contents of Zipfile via HTTP - Stack Overflow

java http streaming zip
Rectangle 27 0

Java supports the gzip format with the GZipInputStream (decompressing) and GZipOutputStream (compressing). Both zip and gzip use the same compressing format internally, the main difference is in the metadata: zip has it at the end of the file, gzip at the beginning (and gzip only supports one enclosed file easily).

For your of streaming one big file, using gzip will be the better thing to do - even more as you don't need access to the metadata.

I'm not sure if the HTTPConnection sends Accept-Encoding: gzip and then handles inflating the content automatically if the server delivers it with Content-Encoding: gzip, but you surely can do it manually if the server simply sends a the .gz file as such (i.e. with Content-Encoding: identity).

(By the way, make sure to read from the stream with not too small buffers, as each deflate call will have a native call overhead, since Java's GZipInputStream uses the native zlib implementation.)

Java: Stream Contents of Zipfile via HTTP - Stack Overflow

java http streaming zip
Rectangle 27 0

thanks, but is this gzip available in the java http implementation?

sure just send a gzipstream and on the server side store the stream to disk. You just wrap the current streams. The gzipstream is the enclosed entity inside the POST or PUT

Java: Stream Contents of Zipfile via HTTP - Stack Overflow

java http streaming zip