blob: b3c7b2319992726473fcfeaa744a955894442bf5 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdlib.h>
#include <fuchsia/net/oldhttp/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include "lib/component/cpp/connect.h"
#include "lib/component/cpp/startup_context.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/macros.h"
namespace examples {
namespace http = ::fuchsia::net::oldhttp;
// ResponseConsumer consumes the response silently.
class ResponseConsumer {
public:
ResponseConsumer(int id) : id_(id) {}
ResponseConsumer() = delete;
void Run(http::URLResponse response) const {
if (response.error) {
printf("#%d: Got error: %d (%s)\n", id_, response.error->code,
response.error->description.get().c_str());
} else {
ReadResponseBody(std::move(response.body->stream()));
}
}
void ReadResponseBody(zx::socket body) const {
for (;;) {
char buf[512];
size_t num_bytes = sizeof(buf);
zx_status_t result = body.read(0u, buf, num_bytes, &num_bytes);
if (result == ZX_ERR_SHOULD_WAIT) {
body.wait_one(ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED,
zx::time::infinite(), nullptr);
} else if (result == ZX_ERR_PEER_CLOSED) {
// not an error
break;
} else if (result == ZX_OK) {
// ignore the data and go to another read.
} else {
printf("#%d: Unexpected error reading response %d\n", id_, result);
break;
}
}
}
private:
int id_;
};
class MWGetApp {
public:
static constexpr int MAX_LOADERS = 100;
MWGetApp(async::Loop* loop)
: context_(component::StartupContext::CreateFromStartupInfo()),
loop_(loop) {
http_service_ = context_->ConnectToEnvironmentService<http::HttpService>();
FXL_DCHECK(loop);
FXL_DCHECK(http_service_);
}
bool Start(const std::vector<std::string>& args) {
if (args.size() != 3) {
printf("usage: %s url num_loaders\n", args[0].c_str());
return false;
}
std::string url(args[1]);
num_loaders_ = atoi(args[2].c_str());
if (num_loaders_ <= 0) {
printf("num_loaders must be positive\n");
return false;
} else if (num_loaders_ > MAX_LOADERS) {
printf("can't exceed the max number of loaders (%d)\n", MAX_LOADERS);
return false;
}
printf("Loading: %s x %d\n", url.c_str(), num_loaders_);
num_done_ = 0;
for (int i = 0; i < num_loaders_; i++) {
http_service_->CreateURLLoader(url_loader_[i].NewRequest());
http::URLRequest request;
request.url = url;
request.method = "GET";
request.auto_follow_redirects = true;
url_loader_[i]->Start(std::move(request),
[this, i](http::URLResponse response) {
ResponseConsumer consumer(i);
consumer.Run(std::move(response));
++num_done_;
printf("[%d] #%d done\n", num_done_, i);
if (num_done_ == num_loaders_) {
printf("All done!\n");
loop_->Quit();
}
});
}
return true;
}
private:
std::unique_ptr<component::StartupContext> context_;
async::Loop* const loop_;
http::HttpServicePtr http_service_;
http::URLLoaderPtr url_loader_[MAX_LOADERS];
int num_loaders_;
int num_done_;
};
} // namespace examples
int main(int argc, const char** argv) {
std::vector<std::string> args(argv, argv + argc);
async::Loop loop(&kAsyncLoopConfigAttachToThread);
examples::MWGetApp app(&loop);
if (app.Start(args))
loop.Run();
return 0;
}