Implement protocol.registerFileProtocol

This commit is contained in:
Cheng Zhao 2015-08-12 15:18:31 +08:00
parent 337460cdc2
commit d2681d2ba1
8 changed files with 383 additions and 88 deletions

View file

@ -8,6 +8,7 @@
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/net/url_request_string_job.h" #include "atom/browser/net/url_request_string_job.h"
#include "atom/browser/net/url_request_async_asar_job.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
@ -46,7 +47,9 @@ mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
return mate::ObjectTemplateBuilder(isolate) return mate::ObjectTemplateBuilder(isolate)
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes) .SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
.SetMethod("registerStringProtocol", .SetMethod("registerStringProtocol",
&Protocol::RegisterProtocol<URLRequestStringJob>); &Protocol::RegisterProtocol<URLRequestStringJob>)
.SetMethod("registerFileProtocol",
&Protocol::RegisterProtocol<UrlRequestAsyncAsarJob>);
} }
void Protocol::RegisterStandardSchemes( void Protocol::RegisterStandardSchemes(

View file

@ -64,14 +64,16 @@ app.once 'ready', ->
catch e catch e
# The chrome-extension: can map a extension URL request to real file path. # The chrome-extension: can map a extension URL request to real file path.
# protocol.registerProtocol 'chrome-extension', (request) -> chromeExtensionHandler = (request, callback) ->
# parsed = url.parse request.url parsed = url.parse request.url
# return unless parsed.hostname and parsed.path? return callback() unless parsed.hostname and parsed.path?
# return unless /extension-\d+/.test parsed.hostname return callback() unless /extension-\d+/.test parsed.hostname
# directory = getPathForHost parsed.hostname directory = getPathForHost parsed.hostname
# return unless directory? return callback() unless directory?
# return new protocol.RequestFileJob(path.join(directory, parsed.path)) callback path.join(directory, parsed.path)
protocol.registerFileProtocol 'chrome-extension', chromeExtensionHandler, ->
console.error 'Unable to register chrome-extension protocol'
BrowserWindow::_loadDevToolsExtensions = (extensionInfoArray) -> BrowserWindow::_loadDevToolsExtensions = (extensionInfoArray) ->
@devToolsWebContents?.executeJavaScript "DevToolsAPI.addExtensions(#{JSON.stringify(extensionInfoArray)});" @devToolsWebContents?.executeJavaScript "DevToolsAPI.addExtensions(#{JSON.stringify(extensionInfoArray)});"

View file

@ -5,45 +5,11 @@
#include "atom/browser/net/asar/asar_protocol_handler.h" #include "atom/browser/net/asar/asar_protocol_handler.h"
#include "atom/browser/net/asar/url_request_asar_job.h" #include "atom/browser/net/asar/url_request_asar_job.h"
#include "atom/common/asar/archive.h"
#include "atom/common/asar/asar_util.h"
#include "net/base/filename_util.h" #include "net/base/filename_util.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/url_request/url_request_error_job.h"
#include "net/url_request/url_request_file_job.h"
namespace asar { namespace asar {
// static
net::URLRequestJob* CreateJobFromPath(
const base::FilePath& full_path,
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const scoped_refptr<base::TaskRunner> file_task_runner) {
// Create asar:// job when the path contains "xxx.asar/", otherwise treat the
// URL request as file://.
base::FilePath asar_path, relative_path;
if (!GetAsarArchivePath(full_path, &asar_path, &relative_path))
return new net::URLRequestFileJob(request, network_delegate, full_path,
file_task_runner);
std::shared_ptr<Archive> archive = GetOrCreateAsarArchive(asar_path);
Archive::FileInfo file_info;
if (!archive || !archive->GetFileInfo(relative_path, &file_info))
return new net::URLRequestErrorJob(request, network_delegate,
net::ERR_FILE_NOT_FOUND);
if (file_info.unpacked) {
base::FilePath real_path;
archive->CopyFileOut(relative_path, &real_path);
return new net::URLRequestFileJob(request, network_delegate, real_path,
file_task_runner);
}
return new URLRequestAsarJob(request, network_delegate, archive,
relative_path, file_info, file_task_runner);
}
AsarProtocolHandler::AsarProtocolHandler( AsarProtocolHandler::AsarProtocolHandler(
const scoped_refptr<base::TaskRunner>& file_task_runner) const scoped_refptr<base::TaskRunner>& file_task_runner)
: file_task_runner_(file_task_runner) {} : file_task_runner_(file_task_runner) {}
@ -56,8 +22,9 @@ net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob(
net::NetworkDelegate* network_delegate) const { net::NetworkDelegate* network_delegate) const {
base::FilePath full_path; base::FilePath full_path;
net::FileURLToFilePath(request->url(), &full_path); net::FileURLToFilePath(request->url(), &full_path);
return CreateJobFromPath(full_path, request, network_delegate, URLRequestAsarJob* job = new URLRequestAsarJob(request, network_delegate);
file_task_runner_); job->Initialize(file_task_runner_, full_path);
return job;
} }
bool AsarProtocolHandler::IsSafeRedirectTarget(const GURL& location) const { bool AsarProtocolHandler::IsSafeRedirectTarget(const GURL& location) const {

View file

@ -6,47 +6,126 @@
#include <string> #include <string>
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
#include "atom/common/asar/archive.h"
#include "atom/common/asar/asar_util.h"
#include "net/base/file_stream.h" #include "net/base/file_stream.h"
#include "net/base/filename_util.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/mime_util.h" #include "net/base/mime_util.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/filter/filter.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request_status.h" #include "net/url_request/url_request_status.h"
#if defined(OS_WIN)
#include "base/win/shortcut.h"
#endif
namespace asar { namespace asar {
URLRequestAsarJob::FileMetaInfo::FileMetaInfo()
: file_size(0),
mime_type_result(false),
file_exists(false),
is_directory(false) {
}
URLRequestAsarJob::URLRequestAsarJob( URLRequestAsarJob::URLRequestAsarJob(
net::URLRequest* request, net::URLRequest* request,
net::NetworkDelegate* network_delegate, net::NetworkDelegate* network_delegate)
std::shared_ptr<Archive> archive,
const base::FilePath& file_path,
const Archive::FileInfo& file_info,
const scoped_refptr<base::TaskRunner>& file_task_runner)
: net::URLRequestJob(request, network_delegate), : net::URLRequestJob(request, network_delegate),
archive_(archive), type_(TYPE_ERROR),
file_path_(file_path),
file_info_(file_info),
stream_(new net::FileStream(file_task_runner)),
remaining_bytes_(0), remaining_bytes_(0),
file_task_runner_(file_task_runner),
weak_ptr_factory_(this) {} weak_ptr_factory_(this) {}
URLRequestAsarJob::~URLRequestAsarJob() {} URLRequestAsarJob::~URLRequestAsarJob() {}
void URLRequestAsarJob::Start() { void URLRequestAsarJob::Initialize(
remaining_bytes_ = static_cast<int64>(file_info_.size); const scoped_refptr<base::TaskRunner> file_task_runner,
const base::FilePath& file_path) {
// Determine whether it is an asar file.
base::FilePath asar_path, relative_path;
if (!GetAsarArchivePath(file_path, &asar_path, &relative_path)) {
InitializeFileJob(file_task_runner, file_path);
return;
}
int flags = base::File::FLAG_OPEN | std::shared_ptr<Archive> archive = GetOrCreateAsarArchive(asar_path);
base::File::FLAG_READ | Archive::FileInfo file_info;
base::File::FLAG_ASYNC; if (!archive || !archive->GetFileInfo(relative_path, &file_info)) {
int rv = stream_->Open(archive_->path(), flags, type_ = TYPE_ERROR;
base::Bind(&URLRequestAsarJob::DidOpen, return;
weak_ptr_factory_.GetWeakPtr())); }
if (rv != net::ERR_IO_PENDING)
DidOpen(rv); if (file_info.unpacked) {
base::FilePath real_path;
archive->CopyFileOut(relative_path, &real_path);
InitializeFileJob(file_task_runner, real_path);
return;
}
InitializeAsarJob(file_task_runner, archive, relative_path, file_info);
}
void URLRequestAsarJob::InitializeAsarJob(
const scoped_refptr<base::TaskRunner> file_task_runner,
std::shared_ptr<Archive> archive,
const base::FilePath& file_path,
const Archive::FileInfo& file_info) {
type_ = TYPE_ASAR;
file_task_runner_ = file_task_runner;
stream_.reset(new net::FileStream(file_task_runner_));
archive_ = archive;
file_path_ = file_path;
file_info_ = file_info;
}
void URLRequestAsarJob::InitializeFileJob(
const scoped_refptr<base::TaskRunner> file_task_runner,
const base::FilePath& file_path) {
type_ = TYPE_FILE;
file_task_runner_ = file_task_runner;
stream_.reset(new net::FileStream(file_task_runner_));
file_path_ = file_path;
}
void URLRequestAsarJob::Start() {
if (type_ == TYPE_ASAR) {
remaining_bytes_ = static_cast<int64>(file_info_.size);
int flags = base::File::FLAG_OPEN |
base::File::FLAG_READ |
base::File::FLAG_ASYNC;
int rv = stream_->Open(archive_->path(), flags,
base::Bind(&URLRequestAsarJob::DidOpen,
weak_ptr_factory_.GetWeakPtr()));
if (rv != net::ERR_IO_PENDING)
DidOpen(rv);
} else if (type_ == TYPE_FILE) {
FileMetaInfo* meta_info = new FileMetaInfo();
file_task_runner_->PostTaskAndReply(
FROM_HERE,
base::Bind(&URLRequestAsarJob::FetchMetaInfo, file_path_,
base::Unretained(meta_info)),
base::Bind(&URLRequestAsarJob::DidFetchMetaInfo,
weak_ptr_factory_.GetWeakPtr(),
base::Owned(meta_info)));
} else {
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_FILE_NOT_FOUND));
}
} }
void URLRequestAsarJob::Kill() { void URLRequestAsarJob::Kill() {
stream_.reset();
weak_ptr_factory_.InvalidateWeakPtrs(); weak_ptr_factory_.InvalidateWeakPtrs();
URLRequestJob::Kill(); URLRequestJob::Kill();
} }
@ -85,8 +164,97 @@ bool URLRequestAsarJob::ReadRawData(net::IOBuffer* dest,
return false; return false;
} }
bool URLRequestAsarJob::IsRedirectResponse(GURL* location,
int* http_status_code) {
if (type_ != TYPE_FILE)
return false;
#if defined(OS_WIN)
// Follow a Windows shortcut.
// We just resolve .lnk file, ignore others.
if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
return false;
base::FilePath new_path = file_path_;
bool resolved;
resolved = base::win::ResolveShortcut(new_path, &new_path, NULL);
// If shortcut is not resolved succesfully, do not redirect.
if (!resolved)
return false;
*location = net::FilePathToFileURL(new_path);
*http_status_code = 301;
return true;
#else
return false;
#endif
}
net::Filter* URLRequestAsarJob::SetupFilter() const {
// Bug 9936 - .svgz files needs to be decompressed.
return LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")
? net::Filter::GZipFactory() : NULL;
}
bool URLRequestAsarJob::GetMimeType(std::string* mime_type) const { bool URLRequestAsarJob::GetMimeType(std::string* mime_type) const {
return net::GetMimeTypeFromFile(file_path_, mime_type); if (type_ == TYPE_ASAR) {
return net::GetMimeTypeFromFile(file_path_, mime_type);
} else {
if (meta_info_.mime_type_result) {
*mime_type = meta_info_.mime_type;
return true;
}
return false;
}
}
void URLRequestAsarJob::SetExtraRequestHeaders(
const net::HttpRequestHeaders& headers) {
std::string range_header;
if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
// We only care about "Range" header here.
std::vector<net::HttpByteRange> ranges;
if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
if (ranges.size() == 1) {
byte_range_ = ranges[0];
} else {
NotifyDone(net::URLRequestStatus(
net::URLRequestStatus::FAILED,
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
}
}
}
}
void URLRequestAsarJob::FetchMetaInfo(const base::FilePath& file_path,
FileMetaInfo* meta_info) {
base::File::Info file_info;
meta_info->file_exists = base::GetFileInfo(file_path, &file_info);
if (meta_info->file_exists) {
meta_info->file_size = file_info.size;
meta_info->is_directory = file_info.is_directory;
}
// On Windows GetMimeTypeFromFile() goes to the registry. Thus it should be
// done in WorkerPool.
meta_info->mime_type_result =
net::GetMimeTypeFromFile(file_path, &meta_info->mime_type);
}
void URLRequestAsarJob::DidFetchMetaInfo(const FileMetaInfo* meta_info) {
meta_info_ = *meta_info;
if (!meta_info_.file_exists || meta_info_.is_directory) {
DidOpen(net::ERR_FILE_NOT_FOUND);
return;
}
int flags = base::File::FLAG_OPEN |
base::File::FLAG_READ |
base::File::FLAG_ASYNC;
int rv = stream_->Open(file_path_, flags,
base::Bind(&URLRequestAsarJob::DidOpen,
weak_ptr_factory_.GetWeakPtr()));
if (rv != net::ERR_IO_PENDING)
DidOpen(rv);
} }
void URLRequestAsarJob::DidOpen(int result) { void URLRequestAsarJob::DidOpen(int result) {
@ -95,24 +263,59 @@ void URLRequestAsarJob::DidOpen(int result) {
return; return;
} }
int rv = stream_->Seek(base::File::FROM_BEGIN, if (type_ == TYPE_ASAR) {
file_info_.offset, int rv = stream_->Seek(base::File::FROM_BEGIN,
base::Bind(&URLRequestAsarJob::DidSeek, file_info_.offset,
weak_ptr_factory_.GetWeakPtr())); base::Bind(&URLRequestAsarJob::DidSeek,
if (rv != net::ERR_IO_PENDING) { weak_ptr_factory_.GetWeakPtr()));
// stream_->Seek() failed, so pass an intentionally erroneous value if (rv != net::ERR_IO_PENDING) {
// into DidSeek(). // stream_->Seek() failed, so pass an intentionally erroneous value
DidSeek(-1); // into DidSeek().
DidSeek(-1);
}
} else {
if (!byte_range_.ComputeBounds(meta_info_.file_size)) {
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
return;
}
remaining_bytes_ = byte_range_.last_byte_position() -
byte_range_.first_byte_position() + 1;
if (remaining_bytes_ > 0 && byte_range_.first_byte_position() != 0) {
int rv = stream_->Seek(base::File::FROM_BEGIN,
byte_range_.first_byte_position(),
base::Bind(&URLRequestAsarJob::DidSeek,
weak_ptr_factory_.GetWeakPtr()));
if (rv != net::ERR_IO_PENDING) {
// stream_->Seek() failed, so pass an intentionally erroneous value
// into DidSeek().
DidSeek(-1);
}
} else {
// We didn't need to call stream_->Seek() at all, so we pass to DidSeek()
// the value that would mean seek success. This way we skip the code
// handling seek failure.
DidSeek(byte_range_.first_byte_position());
}
} }
} }
void URLRequestAsarJob::DidSeek(int64 result) { void URLRequestAsarJob::DidSeek(int64 result) {
if (result != static_cast<int64>(file_info_.offset)) { if (type_ == TYPE_ASAR) {
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, if (result != static_cast<int64>(file_info_.offset)) {
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
return; net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
return;
}
} else {
if (result != byte_range_.first_byte_position()) {
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
return;
}
} }
set_expected_content_size(remaining_bytes_); set_expected_content_size(remaining_bytes_);
NotifyHeadersComplete(); NotifyHeadersComplete();
} }

View file

@ -8,10 +8,12 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "atom/browser/net/js_asker.h"
#include "atom/common/asar/archive.h" #include "atom/common/asar/archive.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "net/http/http_byte_range.h"
#include "net/url_request/url_request_job.h" #include "net/url_request/url_request_job.h"
namespace base { namespace base {
@ -34,11 +36,20 @@ net::URLRequestJob* CreateJobFromPath(
class URLRequestAsarJob : public net::URLRequestJob { class URLRequestAsarJob : public net::URLRequestJob {
public: public:
URLRequestAsarJob(net::URLRequest* request, URLRequestAsarJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate, net::NetworkDelegate* network_delegate);
std::shared_ptr<Archive> archive,
const base::FilePath& file_path, void Initialize(const scoped_refptr<base::TaskRunner> file_task_runner,
const Archive::FileInfo& file_info, const base::FilePath& file_path);
const scoped_refptr<base::TaskRunner>& file_task_runner);
protected:
virtual ~URLRequestAsarJob();
void InitializeAsarJob(const scoped_refptr<base::TaskRunner> file_task_runner,
std::shared_ptr<Archive> archive,
const base::FilePath& file_path,
const Archive::FileInfo& file_info);
void InitializeFileJob(const scoped_refptr<base::TaskRunner> file_task_runner,
const base::FilePath& file_path);
// net::URLRequestJob: // net::URLRequestJob:
void Start() override; void Start() override;
@ -46,12 +57,39 @@ class URLRequestAsarJob : public net::URLRequestJob {
bool ReadRawData(net::IOBuffer* buf, bool ReadRawData(net::IOBuffer* buf,
int buf_size, int buf_size,
int* bytes_read) override; int* bytes_read) override;
bool IsRedirectResponse(GURL* location, int* http_status_code) override;
net::Filter* SetupFilter() const override;
bool GetMimeType(std::string* mime_type) const override; bool GetMimeType(std::string* mime_type) const override;
void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
protected:
virtual ~URLRequestAsarJob();
private: private:
// Meta information about the file. It's used as a member in the
// URLRequestFileJob and also passed between threads because disk access is
// necessary to obtain it.
struct FileMetaInfo {
FileMetaInfo();
// Size of the file.
int64 file_size;
// Mime type associated with the file.
std::string mime_type;
// Result returned from GetMimeTypeFromFile(), i.e. flag showing whether
// obtaining of the mime type was successful.
bool mime_type_result;
// Flag showing whether the file exists.
bool file_exists;
// Flag showing whether the file name actually refers to a directory.
bool is_directory;
};
// Fetches file info on a background thread.
static void FetchMetaInfo(const base::FilePath& file_path,
FileMetaInfo* meta_info);
// Callback after fetching file info on a background thread.
void DidFetchMetaInfo(const FileMetaInfo* meta_info);
// Callback after opening file on a background thread. // Callback after opening file on a background thread.
void DidOpen(int result); void DidOpen(int result);
@ -62,14 +100,24 @@ class URLRequestAsarJob : public net::URLRequestJob {
// Callback after data is asynchronously read from the file into |buf|. // Callback after data is asynchronously read from the file into |buf|.
void DidRead(scoped_refptr<net::IOBuffer> buf, int result); void DidRead(scoped_refptr<net::IOBuffer> buf, int result);
// The type of this job.
enum JobType {
TYPE_ERROR,
TYPE_ASAR,
TYPE_FILE,
};
JobType type_;
std::shared_ptr<Archive> archive_; std::shared_ptr<Archive> archive_;
base::FilePath file_path_; base::FilePath file_path_;
Archive::FileInfo file_info_; Archive::FileInfo file_info_;
scoped_ptr<net::FileStream> stream_; scoped_ptr<net::FileStream> stream_;
int64 remaining_bytes_; FileMetaInfo meta_info_;
scoped_refptr<base::TaskRunner> file_task_runner_;
const scoped_refptr<base::TaskRunner> file_task_runner_; net::HttpByteRange byte_range_;
int64 remaining_bytes_;
base::WeakPtrFactory<URLRequestAsarJob> weak_ptr_factory_; base::WeakPtrFactory<URLRequestAsarJob> weak_ptr_factory_;

View file

@ -0,0 +1,40 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/net/url_request_async_asar_job.h"
namespace atom {
UrlRequestAsyncAsarJob::UrlRequestAsyncAsarJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
v8::Isolate* isolate,
const JavaScriptHandler& handler)
: JsAsker<asar::URLRequestAsarJob>(request, network_delegate, isolate,
handler) {
}
void UrlRequestAsyncAsarJob::StartAsync(scoped_ptr<base::Value> options) {
base::FilePath::StringType file_path;
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
static_cast<base::DictionaryValue*>(options.get())->GetString(
"path", &file_path);
} else if (options->IsType(base::Value::TYPE_STRING)) {
options->GetAsString(&file_path);
}
if (file_path.empty()) {
NotifyStartError(net::URLRequestStatus(
net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED));
} else {
asar::URLRequestAsarJob::Initialize(
content::BrowserThread::GetBlockingPool()->
GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
base::FilePath(file_path));
asar::URLRequestAsarJob::Start();
}
}
} // namespace atom

View file

@ -0,0 +1,30 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
#define ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
#include "atom/browser/net/asar/url_request_asar_job.h"
#include "atom/browser/net/js_asker.h"
namespace atom {
// Like URLRequestAsarJob, but asks the JavaScript handler for file path.
class UrlRequestAsyncAsarJob : public JsAsker<asar::URLRequestAsarJob> {
public:
UrlRequestAsyncAsarJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate,
v8::Isolate* isolate,
const JavaScriptHandler& handler);
// JsAsker:
void StartAsync(scoped_ptr<base::Value> options) override;
private:
DISALLOW_COPY_AND_ASSIGN(UrlRequestAsyncAsarJob);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_

View file

@ -156,6 +156,8 @@
'atom/browser/net/http_protocol_handler.h', 'atom/browser/net/http_protocol_handler.h',
'atom/browser/net/js_asker.cc', 'atom/browser/net/js_asker.cc',
'atom/browser/net/js_asker.h', 'atom/browser/net/js_asker.h',
'atom/browser/net/url_request_async_asar_job.cc',
'atom/browser/net/url_request_async_asar_job.h',
'atom/browser/net/url_request_string_job.cc', 'atom/browser/net/url_request_string_job.cc',
'atom/browser/net/url_request_string_job.h', 'atom/browser/net/url_request_string_job.h',
'atom/browser/net/url_request_buffer_job.cc', 'atom/browser/net/url_request_buffer_job.cc',