Changeset 6071


Ignore:
Timestamp:
Jul 30, 2012, 2:03:29 PM (11 years ago)
Author:
Nicklas Nordborg
Message:

Fixes #1705: Add support for pausing and resuming file downloads

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/clients/web/net/sf/basedb/clients/web/servlet/Download.java

    r6070 r6071  
    6969  private static final Pattern findId = Pattern.compile("/-([0-9a-f]+)-(/.*)$");
    7070
     71  // Find start+end byte in Range header. We support simplified syntax only: bytes=start-(end)
     72  private static final Pattern findRange = Pattern.compile("bytes=(\\d+)-(\\d*)");
     73 
    7174  private String defaultMimeType = "text/plain";
    7275  private String forceMimeType = null;
     
    9699    String pathInfo = usePathInfo ? request.getPathInfo() :
    97100      URLDecoder.decode(request.getRequestURI(), "UTF-8").replace(contextPath+servletPath, "");
     101    String range = request.getHeader("Range");
     102    String ifRange = request.getHeader("If-Range");
     103   
    98104    /*
    99105      The pathInfo is expected to be like:
     
    126132      return;
    127133    }
     134   
     135    // Check if a "Range" has been specifed (eg. when resuming a paused download)
     136    // We only allow a simplified syntax
     137    long startByte = 0;
     138    long endByte = 0;
     139    if (range != null)
     140    {
     141      m = findRange.matcher(range);
     142      if (m.matches())
     143      {
     144        startByte = Values.getLong(m.group(1), 0);
     145        endByte = Values.getLong(m.group(2), 0);
     146      }
     147      else
     148      {
     149        // Ignore range request and serve the full file
     150        range = null;
     151      }
     152    }
     153   
     154    //System.out.println("Range: " + range + "; startByte=" + startByte + "; endByte="+endByte);
    128155
    129156    SessionControl sc = null;
     
    155182      dc = sc.newDbControl();
    156183      f = File.getByPath(dc, path, false);
     184      // The ETag is used to support pause/resume when downloading
     185      // Seems to work without it in Firefox but not in IE
     186      // We use the MD5 checksum if available and the version otherwise
     187      String eTag = "\"" + (f.getMd5() == null ? f.getVersion() : f.getMd5()) + "\"";
    157188      String mimeType = forceMimeType != null ? forceMimeType : f.getMimeType();
    158189      if (mimeType == null)
     
    163194      if (f.getCharacterSet() != null) response.setCharacterEncoding(f.getCharacterSet());
    164195      if (download) response.setHeader("Content-Disposition", "attachment;filename=\""+f.getName() + "\"");
    165       long size = f.getSize();
    166       if (size >= 0 && size < Integer.MAX_VALUE) response.setContentLength((int)size);
    167       in = f.getDownloadStream(0);
     196     
     197      long fileSize = f.getSize();
     198      long contentSize = fileSize;
     199      if (range != null && (eTag.equals(ifRange) || ifRange == null))
     200      {
     201        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
     202        String contentRange = "";
     203        if (fileSize >= 0)
     204        {
     205          // Adjust the range and size if the file size is known
     206          if (endByte > fileSize || endByte == 0) endByte = fileSize-1;
     207          contentRange = "bytes " + startByte + "-" + endByte + "/" + fileSize;
     208          contentSize = endByte - startByte + 1;
     209        }
     210        else
     211        {
     212          // Special case for unknown file size
     213          contentRange = "bytes " + startByte + "-/*";
     214        }
     215        response.setHeader("Content-Range", contentRange);
     216        //System.out.println("Content-Range: " + contentRange);
     217      }
     218      if (contentSize >= 0 && contentSize < Integer.MAX_VALUE) response.setContentLength((int)contentSize);
     219      response.setHeader("ETag", eTag);
     220     
     221      in = f.getDownloadStream(startByte);
    168222      dc.close();
    169223      out = response.getOutputStream();
Note: See TracChangeset for help on using the changeset viewer.