proxygen
StaticHandler.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #include "StaticHandler.h"
11 
15 #include <folly/FileUtil.h>
17 
18 using namespace proxygen;
19 
20 namespace StaticService {
21 
28 void StaticHandler::onRequest(std::unique_ptr<HTTPMessage> headers) noexcept {
29  if (headers->getMethod() != HTTPMethod::GET) {
30  ResponseBuilder(downstream_)
31  .status(400, "Bad method")
32  .body("Only GET is supported")
33  .sendWithEOM();
34  return;
35  }
36  // a real webserver would validate this path didn't contain malicious
37  // characters like '//' or '..'
38  try {
39  // + 1 to kill leading /
40  file_ = std::make_unique<folly::File>(headers->getPath().c_str() + 1);
41  } catch (const std::system_error& ex) {
42  ResponseBuilder(downstream_)
43  .status(404, "Not Found")
44  .body(folly::to<std::string>("Could not find ", headers->getPath(),
45  " ex=", folly::exceptionStr(ex)))
46  .sendWithEOM();
47  return;
48  }
49  ResponseBuilder(downstream_)
50  .status(200, "Ok")
51  .send();
52  // use a CPU executor since read(2) of a file can block
53  readFileScheduled_ = true;
54  folly::getCPUExecutor()->add(
57 }
58 
61  while (file_ && !paused_) {
62  // read 4k-ish chunks and foward each one to the client
63  auto data = buf.preallocate(4000, 4000);
64  auto rc = folly::readNoInt(file_->fd(), data.first, data.second);
65  if (rc < 0) {
66  // error
67  VLOG(4) << "Read error=" << rc;
68  file_.reset();
69  evb->runInEventBaseThread([this] {
70  LOG(ERROR) << "Error reading file";
71  downstream_->sendAbort();
72  });
73  break;
74  } else if (rc == 0) {
75  // done
76  file_.reset();
77  VLOG(4) << "Read EOF";
78  evb->runInEventBaseThread([this] {
79  ResponseBuilder(downstream_)
80  .sendWithEOM();
81  });
82  break;
83  } else {
84  buf.postallocate(rc);
85  evb->runInEventBaseThread([this, body=buf.move()] () mutable {
86  ResponseBuilder(downstream_)
87  .body(std::move(body))
88  .send();
89  });
90  }
91  }
92 
93  // Notify the request thread that we terminated the readFile loop
94  evb->runInEventBaseThread([this] {
95  readFileScheduled_ = false;
96  if (!checkForCompletion() && !paused_) {
97  VLOG(4) << "Resuming deferred readFile";
98  onEgressResumed();
99  }
100  });
101 }
102 
103 void StaticHandler::onEgressPaused() noexcept {
104  // This will terminate readFile soon
105  VLOG(4) << "StaticHandler paused";
106  paused_ = true;
107 }
108 
109 void StaticHandler::onEgressResumed() noexcept {
110  VLOG(4) << "StaticHandler resumed";
111  paused_ = false;
112  // If readFileScheduled_, it will reschedule itself
113  if (!readFileScheduled_ && file_) {
114  readFileScheduled_ = true;
115  folly::getCPUExecutor()->add(
118  } else {
119  VLOG(4) << "Deferred scheduling readFile";
120  }
121 }
122 
123 
124 void StaticHandler::onBody(std::unique_ptr<folly::IOBuf> /*body*/) noexcept {
125  // ignore, only support GET
126 }
127 
128 void StaticHandler::onEOM() noexcept {
129 }
130 
131 void StaticHandler::onUpgrade(UpgradeProtocol /*protocol*/) noexcept {
132  // handler doesn't support upgrades
133 }
134 
135 void StaticHandler::requestComplete() noexcept {
136  finished_ = true;
137  paused_ = true;
138  checkForCompletion();
139 }
140 
141 void StaticHandler::onError(ProxygenError /*err*/) noexcept {
142  finished_ = true;
143  paused_ = true;
144  checkForCompletion();
145 }
146 
147 bool StaticHandler::checkForCompletion() {
148  if (finished_ && !readFileScheduled_) {
149  VLOG(4) << "deleting StaticHandler";
150  delete this;
151  return true;
152  }
153  return false;
154 }
155 
156 }
bool readFile(int fd, Container &out, size_t num_bytes=std::numeric_limits< size_t >::max())
Definition: FileUtil.h:125
ResponseBuilder & status(uint16_t code, const std::string &message)
fbstring exceptionStr(const std::exception &e)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
EventBase * getEventBase()
ssize_t readNoInt(int fd, void *buf, size_t count)
Definition: FileUtil.cpp:102
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
ResponseBuilder & body(std::unique_ptr< folly::IOBuf > bodyIn)
requires E e noexcept(noexcept(s.error(std::move(e))))
static EventBaseManager * get()
std::pair< void *, std::size_t > preallocate(std::size_t min, std::size_t newAllocationSize, std::size_t max=std::numeric_limits< std::size_t >::max())
Definition: IOBufQueue.h:356
bool runInEventBaseThread(void(*fn)(T *), T *arg)
Definition: EventBase.h:794
std::shared_ptr< Executor > getCPUExecutor()
int bind(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:76
void postallocate(std::size_t n)
Definition: IOBufQueue.h:380
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43