private FSEntry GetEntry(string uri) { // Request URIs must never contain \ (only /) if (uri.Contains("\\")) { return(null); } // Make sure the URI starts with the service URI, and prodived it does, strip // off that part. if (!uri.StartsWith(ServiceURI)) { return(null); } uri = uri.Substring(ServiceURI.Length); // Get the file or directory from the URI string[] parts = uri.Split( new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); FSDir dir = m_root, parent = null; for (int i = 0; i < parts.Length; i++) { parent = dir; dir = dir.GetDir(parts[i]); // Should we get a null directory we have 2 cases: // 1. This is NOT the last loop iteration, implying that we've hit a not found. // 2. This IS the last loop iteration, meaning that the last part of the file // string may be a file name and/or may be a not found. We fall through to // the code after this loop in that case. if (null == dir && i != parts.Length - 1) { return(null); } } // If 'dir' is non-null at this point then we return it if (null != dir) { return(dir); } // Coming here implies it's a file name return(parent.GetFile(parts[parts.Length - 1])); }
private static ZipExtractionStats ExtractZip(ZipArchive zipA, FSDir targetDirectory, ZipExtractionOptions options) { // Keep track of the number of entries encountered and extracted ZipExtractionStats stats = new ZipExtractionStats(); // Loop through entries and extract foreach (ZipArchiveEntry entry in zipA.Entries) { stats.NumEntriesSeen++; bool skipThisEntry = false; FSDir targetDir = targetDirectory; // Split the full name on '/' string[] pieces = entry.FullName.Split('/'); int i; for (i = 0; i < pieces.Length - 1; i++) { targetDir = targetDir.CreateDir(pieces[i]); if (null == targetDir) { skipThisEntry = true; break; } } // Skip this entry if need be if (skipThisEntry) { continue; } // At this point pieces[i] is the file we need to create in targetDir if (targetDir.GetFile(pieces[i]) != null && !options.Overwrite) { // We can't overwrite the file continue; } FSFile fileForEntry = targetDir.CreateFile(pieces[i]); if (null == fileForEntry) { continue; } // Open the zip entry stream for reading and the FSFile for writing. Notice that despite // the possibility of failure to open the source stream from the zip file entry, we've // already created the FSFile in the target directory. This is intentional. If we fail // to extract a file, then a 0-byte placeholder is desired (for now, may change later). Stream src = entry.Open(); if (src == null) { continue; } Stream dst = fileForEntry.OpenReadWrite(); if (dst == null) { src.Dispose(); continue; } // Copy the contents byte[] buf = new byte[8192]; while (true) { int bytesRead = src.Read(buf, 0, buf.Length); if (bytesRead <= 0) { break; } dst.Write(buf, 0, bytesRead); } // Clean up and increment number of files extracted src.Dispose(); dst.Dispose(); stats.NumEntriesExtracted++; } return(stats); }
/// <summary> /// Request handler function /// </summary> public override void Handler(WebRequest req) { if (m_disposed) { throw new ObjectDisposedException("FileWebServer"); } if ("POST" == req.Method) { HandlePost(req); return; } // Handle uploads if ("PUT" == req.Method) { HandlePut(req); return; } // If it's anything other than GET at this point then it's not implemented if (req.Method != "GET") { m_logger.WriteLine( " Method was \"" + req.Method + "\" -> sending not implemented response"); req.WriteNotImplementedResponse( "<html><h1>HTTP method "" + req.Method + "" is not implemented</h1></html>"); return; } // First get rid of formatting on requested file string toGet = req.URIDecoded; // Requested file/content name must never contain \ (only /) if (toGet.Contains("\\")) { m_logger.WriteLine( " URI contains \"\\\" -> sending 400 response"); req.WriteBadRequestResponse(); return; } m_logger.WriteLine("Got request for \"" + toGet + "\""); // Make sure the URL starts with the service URL, and prodived it does, strip // off that part. if (!toGet.StartsWith(ServiceURI)) { req.WriteNotFoundResponse(); return; } toGet = toGet.Substring(ServiceURI.Length); // Get the file or directory that we need to serve string[] parts = toGet.Split( new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); FSDir dir = m_root, parent = null; for (int i = 0; i < parts.Length; i++) { parent = dir; dir = dir.GetDir(parts[i]); // Should we get a null directory we have 2 cases: // 1. This is NOT the last loop iteration, implying that we've hit a not found. // 2. This IS the last loop iteration, meaning that the last part of the file // string may be a file name and/or may be a not found. We fall through to // the code after this loop in that case. if (null == dir && i != parts.Length - 1) { if (null != m_onFileNotFound) { // Invoke custom handler m_onFileNotFound(this, toGet, req); } else { req.WriteNotFoundResponse(); } return; } } // If 'dir' is non-null at this point then it's a request for a listing of files in // that directory. if (null != dir) { m_logger.WriteLine(" Sending directory listing as response"); // Build response and send it string response = m_onNeedDirList(dir); req.WriteHTMLResponse(response); // That's all we need for a directory listing return; } // Coming here implies a file name FSFile file = parent.GetFile(parts[parts.Length - 1]); // If it doesn't exist then we respond with a file-not-found response if (null == file) { if (null != m_onFileNotFound) // custom handler { m_logger.WriteLine(" File not found -> invoking external handler"); m_onFileNotFound(this, parts[parts.Length - 1], req); } else { m_logger.WriteLine(" File not found -> sending 404 response"); // If we don't have a handler for file-not-found then we use the generic 404 req.WriteNotFoundResponse(); } return; } // File DOES exist, so we write the file data as the response m_logger.WriteLine(" Sending file contents as response"); WriteFileResponse(req, file); }