Module: Zipline

Defined in:
lib/zipline.rb,
lib/zipline/version.rb,
lib/zipline/chunked_body.rb,
lib/zipline/tempfile_body.rb,
lib/zipline/zip_generator.rb

Overview

this class acts as a streaming body for rails initialize it with an array of the files you want to zip

Defined Under Namespace

Classes: Chunked, TempfileBody, ZipGenerator

Constant Summary collapse

VERSION =
"1.6.0"

Instance Method Summary collapse

Instance Method Details

#zipline(files, zipname = 'zipline.zip', **kwargs_for_new) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/zipline.rb', line 17

def zipline(files, zipname = 'zipline.zip', **kwargs_for_new)
  zip_generator = ZipGenerator.new(files, **kwargs_for_new)
  headers['Content-Disposition'] = ContentDisposition.format(disposition: 'attachment', filename: zipname)
  headers['Content-Type'] = Mime::Type.lookup_by_extension('zip').to_s
  response.sending_file = true
  response.cache_control[:public] ||= false

  # Disables Rack::ETag if it is enabled (prevent buffering)
  # see https://github.com/rack/rack/issues/1619#issuecomment-606315714
  self.response.headers['Last-Modified'] = Time.now.httpdate

  if request.get_header("HTTP_VERSION") == "HTTP/1.0"
    # If HTTP/1.0 is used it is not possible to stream, and if that happens it usually will be
    # unclear why buffering is happening. Some info in the log is the least one can do.
    logger.warn { "The downstream HTTP proxy/LB insists on HTTP/1.0 protocol, ZIP response will be buffered." } if logger

    # If we use Rack::ContentLength it would run through our ZIP block twice - once to calculate the content length
    # of the response, and once - to serve. We can trade performance for disk space and buffer the response into a Tempfile
    # since we are already buffering.
    tempfile_body = TempfileBody.new(request.env, zip_generator)
    headers["Content-Length"] = tempfile_body.size.to_s
    headers["X-Zipline-Output"] = "buffered"
    self.response_body = tempfile_body
  else
    # Disable buffering for both nginx and Google Load Balancer, see
    # https://cloud.google.com/appengine/docs/flexible/how-requests-are-handled?tab=python#x-accel-buffering
    response.headers["X-Accel-Buffering"] = "no"

    # Make sure Rack::ContentLength does not try to compute a content length,
    # and remove the one already set
    headers.delete("Content-Length")

    # and send out in chunked encoding
    headers["Transfer-Encoding"] = "chunked"
    headers["X-Zipline-Output"] = "streamed"
    self.response_body = Chunked.new(zip_generator)
  end
end