fastcgi++
A C++ FastCGI/Web API
fcgistreambuf.cpp
Go to the documentation of this file.
1 
10 /*******************************************************************************
11 * Copyright (C) 2017 Eddie Carle [eddie@isatec.ca] *
12 * *
13 * This file is part of fastcgi++. *
14 * *
15 * fastcgi++ is free software: you can redistribute it and/or modify it under *
16 * the terms of the GNU Lesser General Public License as published by the Free *
17 * Software Foundation, either version 3 of the License, or (at your option) *
18 * any later version. *
19 * *
20 * fastcgi++ is distributed in the hope that it will be useful, but WITHOUT ANY *
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for *
23 * more details. *
24 * *
25 * You should have received a copy of the GNU Lesser General Public License *
26 * along with fastcgi++. If not, see <http://www.gnu.org/licenses/>. *
27 *******************************************************************************/
28 
30 #include "fastcgi++/log.hpp"
31 
32 #include <codecvt>
33 #include <algorithm>
34 
35 namespace Fastcgipp
36 {
37  template <> bool
39  {
40  const std::codecvt_utf8<char_type> converter;
41  std::codecvt_base::result result;
42  Block record;
43  size_t count;
44  mbstate_t state = mbstate_t();
45  char* toNext;
46  const char_type* fromNext;
47 
48  while((count = this->pptr() - this->pbase()) != 0)
49  {
50  record.reserve(sizeof(Protocol::Header)
51  +std::min(static_cast<size_t>(0xffffU),
52  (count*converter.max_length()+Protocol::chunkSize-1)
54 
56  = *reinterpret_cast<Protocol::Header*>(record.begin());
57 
58  result = converter.out(
59  state,
60  this->pbase(),
61  this->pptr(),
62  fromNext,
63  record.begin()+sizeof(Protocol::Header),
64  &*record.end(),
65  toNext);
66 
67  if(result == std::codecvt_base::error
68  || result == std::codecvt_base::noconv)
69  {
70  ERROR_LOG("FcgiStreambuf code conversion failed")
71  pbump(-count);
72  return false;
73  }
74  pbump(-(fromNext - this->pbase()));
75  record.size((toNext-record.begin()+Protocol::chunkSize-1)
76  /Protocol::chunkSize*Protocol::chunkSize);
77 
78  header.version = Protocol::version;
79  header.type = m_type;
80  header.fcgiId = m_id.m_id;
81  header.contentLength =
82  toNext-record.begin()-sizeof(Protocol::Header);
83  header.paddingLength =
84  record.size()-header.contentLength-sizeof(Protocol::Header);
85 
86  send(m_id.m_socket, std::move(record));
87  }
88 
89  return true;
90  }
91 
92  template <>
94  {
95  Block record;
96  size_t count;
97 
98  while((count = this->pptr() - this->pbase()) != 0)
99  {
100  record.size(sizeof(Protocol::Header)
101  +std::min(static_cast<size_t>(0xffffU),
102  (count+Protocol::chunkSize-1)
104 
106  = *reinterpret_cast<Protocol::Header*>(record.begin());
107  header.contentLength = std::min(
108  count,
109  record.size()-sizeof(Protocol::Header));
110 
111  std::copy(
112  this->pbase(),
113  this->pbase()+header.contentLength,
114  record.begin()+sizeof(Protocol::Header));
115 
116  pbump(-header.contentLength);
117 
118  header.version = Protocol::version;
119  header.type = m_type;
120  header.fcgiId = m_id.m_id;
121  header.paddingLength =
122  record.size()-header.contentLength-sizeof(Protocol::Header);
123 
124  send(m_id.m_socket, std::move(record));
125  }
126 
127  return true;
128  }
129 }
130 
131 template <class charT, class traits>
134 {
135  if(!emptyBuffer())
136  return traits_type::eof();
137  if(!traits_type::eq_int_type(c, traits_type::eof()))
138  return this->sputc(c);
139  else
140  return traits_type::not_eof(c);
141 }
142 
143 template <class charT, class traits>
145  const char* data,
146  size_t size)
147 {
148  emptyBuffer();
149  Block record;
150 
151  while(size != 0)
152  {
153  record.size(sizeof(Protocol::Header)
154  +std::min(static_cast<size_t>(0xffffU),
155  (size+Protocol::chunkSize-1)
157 
159  = *reinterpret_cast<Protocol::Header*>(record.begin());
160  header.contentLength = std::min(
161  size,
162  record.size()-sizeof(Protocol::Header));
163 
164  std::copy(
165  data,
166  data+header.contentLength,
167  record.begin()+sizeof(Protocol::Header));
168 
169  size -= header.contentLength;
170  data += header.contentLength;
171 
172  header.version = Protocol::version;
173  header.type = m_type;
174  header.fcgiId = m_id.m_id;
175  header.paddingLength =
176  record.size()-header.contentLength-sizeof(Protocol::Header);
177 
178  send(m_id.m_socket, std::move(record));
179  }
180 }
181 
182 template <class charT, class traits>
184  std::basic_istream<char>& stream)
185 {
186  const ssize_t maxContentLength = 0xffff;
187  emptyBuffer();
188  Block record;
189 
190  do
191  {
192  record.reserve(sizeof(Protocol::Header) + maxContentLength);
193 
195  = *reinterpret_cast<Protocol::Header*>(record.begin());
196 
197  stream.read(record.begin()+sizeof(Protocol::Header), maxContentLength);
198  header.contentLength = stream.gcount();
199 
200  record.size((header.contentLength
201  +sizeof(Protocol::Header)
204 
205  header.version = Protocol::version;
206  header.type = m_type;
207  header.fcgiId = m_id.m_id;
208  header.paddingLength =
209  record.size()-header.contentLength-sizeof(Protocol::Header);
210 
211  send(m_id.m_socket, std::move(record));
212  } while(stream.gcount() < maxContentLength);
213 }
214 
BigEndian< FcgiId > fcgiId
Request ID.
Definition: protocol.hpp:301
BigEndian< uint16_t > contentLength
Content length.
Definition: protocol.hpp:304
Topmost namespace for the fastcgi++ library.
RecordType type
Record type.
Definition: protocol.hpp:298
void header(Level level)
Send a log header to logstream.
Definition: log.cpp:107
Data structure used as the header for FastCGI records.
Definition: protocol.hpp:292
size_t size() const
See the relevant data size.
Definition: block.hpp:94
size_t reserve() const
See the reserve size.
Definition: block.hpp:80
Stream buffer class for output of client data through FastCGI.
uint8_t version
FastCGI version number.
Definition: protocol.hpp:295
const int chunkSize
All FastCGI records will be a multiple of this many bytes.
Definition: protocol.hpp:160
std::basic_streambuf< charT, traits >::int_type int_type
std::basic_streambuf< charT, traits >::char_type char_type
char * end()
Pointer to 1+ the last element.
Definition: block.hpp:115
#define ERROR_LOG(data)
Log any "errors" that can be recovered from.
Definition: log.hpp:107
Declares the Fastcgipp debugging/logging facilities.
Declares the FcgiStreambuf class.
uint8_t paddingLength
Length of record padding.
Definition: protocol.hpp:307
int_type overflow(int_type c=traits_type::eof())
const int version
The version of the FastCGI protocol that this adheres to.
Definition: protocol.hpp:157
void dump(const char *data, size_t size)
Dumps raw data directly into the FastCGI protocol.
Data structure to hold a block of raw data.
Definition: block.hpp:44
char * begin()
Pointer to the first element.
Definition: block.hpp:103