NCBI C++ ToolKit
ncbicgir.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbicgir.cpp 95087 2021-10-06 11:13:00Z grichenk $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors: Eugene Vasilchenko, Denis Vakatov
27 *
28 * File Description:
29 * CCgiResponse -- CGI response generator class
30 *
31 */
32 
33 
34 #include <ncbi_pch.hpp>
35 #include <corelib/request_ctx.hpp>
36 #include <cgi/ncbicgir.hpp>
37 #include <cgi/cgi_exception.hpp>
38 #include <cgi/cgi_session.hpp>
39 #include <cgi/cgictx.hpp>
40 #include <cgi/cgiapp.hpp>
42 #include <cgi/error_codes.hpp>
43 #include <time.h>
44 
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #else
48 # define STDOUT_FILENO 1
49 #endif
50 
51 
52 #define NCBI_USE_ERRCODE_X Cgi_Response
53 
54 
56 
57 
58 const char* CCgiResponse::sm_ContentTypeName = "Content-Type";
59 const char* CCgiResponse::sm_LocationName = "Location";
60 const char* CCgiResponse::sm_ContentTypeDefault = "text/html";
61 const char* CCgiResponse::sm_ContentTypeMixed = "multipart/mixed";
62 const char* CCgiResponse::sm_ContentTypeRelated = "multipart/related";
63 const char* CCgiResponse::sm_ContentTypeXMR = "multipart/x-mixed-replace";
64 const char* CCgiResponse::sm_ContentDispoName = "Content-Disposition";
65 const char* CCgiResponse::sm_FilenamePrefix = "attachment; filename=\"";
66 const char* CCgiResponse::sm_HTTPStatusName = "Status";
67 const char* CCgiResponse::sm_HTTPStatusDefault = "200 OK";
68 const char* CCgiResponse::sm_BoundaryPrefix = "NCBI_CGI_Boundary_";
69 const char* CCgiResponse::sm_CacheControl = "Cache-Control";
70 const char* CCgiResponse::sm_AcceptRanges = "Accept-Ranges";
71 const char* CCgiResponse::sm_AcceptRangesBytes = "bytes";
72 const char* CCgiResponse::sm_ContentRange = "Content-Range";
73 
74 NCBI_PARAM_DEF_IN_SCOPE(bool, CGI, ThrowOnBadOutput, true, CCgiResponse);
75 NCBI_PARAM_DEF_IN_SCOPE(bool, CGI, ExceptionAfterHEAD, false, CCgiResponse);
76 
77 
78 inline bool s_ZeroTime(const tm& date)
79 {
80  static const tm kZeroTime = { 0 };
81  return ::memcmp(&date, &kZeroTime, sizeof(tm)) == 0;
82 }
83 
84 
86  : m_IsRawCgi(false),
87  m_IsMultipart(eMultipart_none),
88  m_BetweenParts(false),
89  m_Output(NULL),
90  m_OutputFD(0),
91  m_HeaderWritten(false),
92  m_RequireWriteHeader(true),
93  m_RequestMethod(CCgiRequest::eMethod_Other),
94  m_Session(NULL),
95  m_DisableTrackingCookie(false),
96  m_Request(0),
97  m_ChunkedTransfer(false)
98 {
99  SetOutput(os ? os : &NcbiCout,
100  os ? ofd : STDOUT_FILENO // "os" on this line is NOT a typo
101  );
102 }
103 
104 
106 {
108 }
109 
110 
111 bool CCgiResponse::HaveHeaderValue(const string& name) const
112 {
113  return m_HeaderValues.find(name) != m_HeaderValues.end();
114 }
115 
116 
117 string CCgiResponse::GetHeaderValue(const string &name) const
118 {
120 
121  return (ptr == m_HeaderValues.end()) ? kEmptyStr : ptr->second;
122 }
123 
124 
125 void CCgiResponse::RemoveHeaderValue(const string& name)
126 {
127  m_HeaderValues.erase(name);
128 }
129 
130 
131 bool CCgiResponse::x_ValidateHeader(const string& name, const string& value) const
132 {
133  // Very basic validation of names - prohibit CR/LF.
134  if (name.find("\n", 0) != NPOS) {
135  return false;
136  }
137  // Values may contain [CR/]LF, but only if followed by space or tab.
138  size_t pos = value.find("\n", 0);
139  while (pos != NPOS) {
140  ++pos;
141  if (pos >= value.size()) break;
142  if (value[pos] != ' ' && value[pos] != '\t') {
143  return false;
144  }
145  pos = value.find("\n", pos);
146  }
147  return true;
148 }
149 
150 
151 void CCgiResponse::SetHeaderValue(const string& name, const string& value)
152 {
153  if ( value.empty() ) {
154  RemoveHeaderValue(name);
155  } else {
156  if ( x_ValidateHeader(name, value) ) {
157  m_HeaderValues[name] = value;
158  }
159  else {
160  NCBI_THROW(CCgiResponseException, eBadHeaderValue,
161  "CCgiResponse::SetHeaderValue() -- "
162  "invalid header name or value: " +
163  name + "=" + value);
164  }
165  }
166 }
167 
168 
169 void CCgiResponse::SetHeaderValue(const string& name, const struct tm& date)
170 {
171  if ( s_ZeroTime(date) ) {
172  RemoveHeaderValue(name);
173  return;
174  }
175 
176  char buff[64];
177  if ( !::strftime(buff, sizeof(buff),
178  "%a, %d %b %Y %H:%M:%S GMT", &date) ) {
180  "CCgiResponse::SetHeaderValue() -- strftime() failed");
181  }
182  SetHeaderValue(name, buff);
183 }
184 
185 
186 void CCgiResponse::SetHeaderValue(const string& name, const CTime& date)
187 {
188  if ( date.IsEmpty()) {
189  RemoveHeaderValue(name);
190  return;
191  }
192  SetHeaderValue(name,
193  date.GetGmtTime().AsString("w, D b Y h:m:s") + " GMT");
194 }
195 
196 
197 void CCgiResponse::SetStatus(unsigned int code, const string& reason)
198 {
199  if (code < 100) {
200  THROW1_TRACE(runtime_error,
201  "CCgiResponse::SetStatus() -- code too small, below 100");
202  }
203  if (code > 999) {
204  THROW1_TRACE(runtime_error,
205  "CCgiResponse::SetStatus() -- code too big, exceeds 999");
206  }
208  (reason.empty() ?
210  : reason));
212 }
213 
214 
216 {
217  if (m_Output && m_ThrowOnBadOutput.Get()) {
218  m_Output->exceptions(m_OutputExpt);
219  }
220 }
221 
222 
224 {
226 
227  m_HeaderWritten = false;
228  m_Output = output;
229  m_OutputFD = fd;
230 
231  // Make the output stream to throw on write if it's in a bad state
232  if (m_Output && m_ThrowOnBadOutput.Get()) {
233  m_OutputExpt = m_Output->exceptions();
234  m_Output->exceptions(IOS_BASE::badbit | IOS_BASE::failbit);
235  }
236 }
237 
238 
240 {
241  bool client_int_ok = TClientConnIntOk::GetDefault() ||
243 
244  if (m_Output &&
245  !client_int_ok &&
247  (m_Output->rdstate() & (IOS_BASE::badbit | IOS_BASE::failbit)) != 0 &&
248  m_ThrowOnBadOutput.Get()) {
249  ERR_POST_X(1, Severity(TClientConnIntSeverity::GetDefault()) <<
250  "CCgiResponse::GetOutput() -- output stream is in bad state");
251  const_cast<CCgiResponse*>(this)->SetThrowOnBadOutput(false);
252  }
253  return m_Output;
254 }
255 
256 
258 {
259  if ( !m_Output ) {
260  THROW1_TRACE(runtime_error, "CCgiResponse::out() on NULL out.stream");
261  }
262  return *GetOutput();
263 }
264 
265 
267 {
268  if (&os == m_Output) {
269  if (m_HeaderWritten) {
270  NCBI_THROW(CCgiResponseException, eDoubleHeader,
271  "CCgiResponse::WriteHeader() -- called more than once");
272  }
273  else {
274  m_HeaderWritten = true;
275  }
276  }
277 
278  // HTTP status line (if "raw CGI" response)
279  bool skip_status = false;
280  if ( IsRawCgi() ) {
281  string status = GetHeaderValue(sm_HTTPStatusName);
282  if ( status.empty() ) {
283  status = sm_HTTPStatusDefault;
284  } else {
285  skip_status = true; // filter out the status from the HTTP header
286  }
287  os << "HTTP/1.1 " << status << HTTP_EOL;
288  }
289 
291  && CCgiUserAgent().GetEngine() == CCgiUserAgent::eEngine_IE) {
292  // MSIE requires multipart responses to start with these extra
293  // headers, which confuse other browsers. :-/
294  os << sm_ContentTypeName << ": message/rfc822" << HTTP_EOL << HTTP_EOL
295  << "Mime-Version: 1.0" << HTTP_EOL;
296  }
297 
298  // Dirty hack (JQuery JSONP for browsers that don't support CORS)
299  if ( !m_JQuery_Callback.empty() ) {
300  CCgiResponse* self = const_cast<CCgiResponse*>(this);
302  self->SetHeaderValue(sm_ContentTypeName, "text/javascript");
303  else
304  self->m_JQuery_Callback.erase();
305  }
306 
307  // Default content type (if it's not specified by user already)
308  switch (m_IsMultipart) {
309  case eMultipart_none:
311  // Do not set content type if status is '204 No Content'
314  << HTTP_EOL;
315  }
316  break;
317  case eMultipart_mixed:
318  os << sm_ContentTypeName << ": " << sm_ContentTypeMixed
319  << "; boundary=" << m_Boundary << HTTP_EOL;
320  break;
321  case eMultipart_related:
323  << "; type=" << (HaveHeaderValue(sm_ContentTypeName)
325  << "; boundary=" << m_Boundary << HTTP_EOL;
326  break;
327  case eMultipart_replace:
328  os << sm_ContentTypeName << ": " << sm_ContentTypeXMR
329  << "; boundary=" << m_Boundary << HTTP_EOL;
330  break;
331  }
332 
333  if (m_Session) {
334  const CCgiCookie* const scookie = m_Session->GetSessionCookie();
335  if (scookie) {
336  const_cast<CCgiResponse*>(this)->m_Cookies.Add(*scookie);
337  }
338  }
341  if (m_Cookies.GetAllCookiesSecure()) temp.SetSecure(true);
342  if (m_Cookies.GetAllCookiesHttpOnly()) temp.SetHttpOnly(true);
343  CCgiResponse* self = const_cast<CCgiResponse*>(this);
344  self->m_Cookies.Add(temp);
345  self->SetHeaderValue(TCGI_TrackingTagName::GetDefault(),
346  m_TrackingCookie->GetValue());
348  self->SetHeaderValue("NCBI-PHID", rctx.GetNextSubHitID("m_"));
349  // Prevent storing the page in public caches.
350  string cc = GetHeaderValue(sm_CacheControl);
351  if ( cc.empty() ) {
352  cc = "private";
353  }
354  else {
355  // 'private' already present?
356  if (NStr::FindNoCase(cc, "private") == NPOS) {
357  // no - check for 'public'
358  size_t pos = NStr::FindNoCase(cc, "public");
359  if (pos != NPOS) {
361  "Cache-Control already set to 'public', "
362  "switching to 'private'");
363  NStr::ReplaceInPlace(cc, "public", "private", pos, 1);
364  }
365  else if (NStr::FindNoCase(cc, "no-cache") == NPOS) {
366  cc.append(", private");
367  }
368  }
369  }
370  self->SetHeaderValue(sm_CacheControl, cc);
371  }
372 
373  // Cookies (if any)
374  if ( !m_Cookies.Empty() ) {
375  os << m_Cookies;
376  }
377 
378  // All header lines (in alphabetical order)
380  if (skip_status && NStr::EqualNocase(i->first, sm_HTTPStatusName)) {
381  continue;
382  } else if (m_IsMultipart != eMultipart_none
383  && NStr::StartsWith(i->first, "Content-", NStr::eNocase)) {
384  continue;
385  }
386  os << i->first << ": " << i->second << HTTP_EOL;
387  }
388  bool chunked_transfer = GetChunkedTransferEnabled();
389  if ( chunked_transfer ) {
390  // Chunked encoding must be the last one.
391  os << "Transfer-Encoding: chunked" << HTTP_EOL;
392  // Add Trailer if necessary.
393  if ( !m_TrailerValues.empty() ) {
394  string trailer;
396  if ( !trailer.empty() ) {
397  trailer.append(", ");
398  }
399  trailer.append(it->first);
400  }
401  os << "Trailer: " << trailer << HTTP_EOL;
402  }
403  }
404 
405  if (m_IsMultipart != eMultipart_none) { // proceed with first part
406  os << HTTP_EOL << "--" << m_Boundary << HTTP_EOL;
409  << HTTP_EOL;
410  }
411  for (TMap::const_iterator it = m_HeaderValues.lower_bound("Content-");
412  it != m_HeaderValues.end()
413  && NStr::StartsWith(it->first, "Content-", NStr::eNocase);
414  ++it) {
415  os << it->first << ": " << it->second << HTTP_EOL;
416  }
417  }
418 
419  // End of header (empty line)
420  os << HTTP_EOL;
421 
422  // Dirty hack (JQuery JSONP for browsers that don't support CORS)
423  if ( !m_JQuery_Callback.empty() ) {
424  os << m_JQuery_Callback << '(';
425  }
426 
427  CCgiStreamWrapper* wrapper = dynamic_cast<CCgiStreamWrapper*>(m_Output);
428  if ( wrapper ) {
430  try {
432  }
433  catch (ios_base::failure&) {
434  }
435  if ( m_ExceptionAfterHEAD.Get() ) {
436  // Optionally stop processing request immediately. The exception
437  // should not be handles by ProcessRequest, but must go up to
438  // the Run() to work correctly.
440  "HEAD response sent.", CCgiException::e200_Ok);
441  }
442  }
443  else if ( chunked_transfer ) {
444  // Chunked encoding is enabled either through the environment,
445  // or due to a header set by the user.
446  try {
448  }
449  catch (ios_base::failure&) {
450  }
451  }
452  }
453 
454  return os;
455 }
456 
457 
458 void CCgiResponse::Finalize(void) const
459 {
461  ERR_POST_X(5, "CCgiResponse::WriteHeader() has not been called - "
462  "HTTP header can be missing.");
463  }
464  if (!m_JQuery_Callback.empty() && m_Output && m_HeaderWritten) {
465  *m_Output << ')';
466  }
467 }
468 
469 
470 void CCgiResponse::SetFilename(const string& name, size_t size)
471 {
472  string disposition = sm_FilenamePrefix + NStr::PrintableString(name) + '"';
473  if (size > 0) {
474  disposition += "; size=";
475  disposition += NStr::SizetToString(size);
476  }
477  SetHeaderValue(sm_ContentDispoName, disposition);
478 }
479 
480 
481 void CCgiResponse::BeginPart(const string& name, const string& type_in,
482  CNcbiOstream& os, size_t size)
483 {
485  if ( !m_BetweenParts ) {
486  os << HTTP_EOL << "--" << m_Boundary << HTTP_EOL;
487  }
488 
489  string type = type_in;
490  if (type.empty() /* && m_IsMultipart == eMultipart_replace */) {
492  }
493  os << sm_ContentTypeName << ": "
494  << (type.empty() ? sm_ContentTypeDefault : type) << HTTP_EOL;
495 
496  if ( !name.empty() ) {
497  os << sm_ContentDispoName << ": " << sm_FilenamePrefix
498  << Printable(name) << '"';
499  if (size > 0) {
500  os << "; size=" << size;
501  }
502  os << HTTP_EOL;
503  } else if (m_IsMultipart != eMultipart_replace) {
504  ERR_POST_X(2, Warning << "multipart content contains anonymous part");
505  }
506 
507  os << HTTP_EOL;
508 }
509 
510 
512 {
514  if ( !m_BetweenParts ) {
515  os << HTTP_EOL << "--" << m_Boundary << HTTP_EOL << NcbiFlush;
516  }
517  m_BetweenParts = true;
518 }
519 
520 
522 {
524  os << HTTP_EOL << "--" << m_Boundary << "--" << HTTP_EOL << NcbiFlush;
525  m_IsMultipart = eMultipart_none; // forbid adding more parts
526 }
527 
528 
529 void CCgiResponse::Flush(void) const
530 {
531  CNcbiOstream* os = GetOutput();
532  if (!os || !os->good()) {
533  return; // Don't try to flush NULL or broken output
534  }
535  *os << NcbiFlush;
536 }
537 
538 
539 void CCgiResponse::SetTrackingCookie(const string& name, const string& value,
540  const string& domain, const string& path,
541  const CTime& exp_time)
542 {
543  m_TrackingCookie.reset(new CCgiCookie(name, value, domain, path));
544 
545  if ( !exp_time.IsEmpty() ) {
546  m_TrackingCookie->SetExpTime(exp_time);
547  }
548  else {
549  // Set the cookie for one year by default.
551  def_exp.AddYear(1);
552  m_TrackingCookie->SetExpTime(def_exp);
553  }
554 }
555 
556 
558 {
560 }
561 
562 
563 void CCgiResponse::SetThrowOnBadOutput(bool throw_on_bad_output)
564 {
565  m_ThrowOnBadOutput.Set(throw_on_bad_output);
566  if (m_Output && throw_on_bad_output) {
567  m_OutputExpt = m_Output->exceptions();
568  m_Output->exceptions(IOS_BASE::badbit | IOS_BASE::failbit);
569  }
570 }
571 
572 
573 void CCgiResponse::SetExceptionAfterHEAD(bool expt_after_head)
574 {
575  m_ExceptionAfterHEAD.Set(expt_after_head);
576 }
577 
578 
580 {
581  string accept_ranges = NStr::TruncateSpaces(GetHeaderValue(sm_AcceptRanges));
582  return NStr::EqualNocase(accept_ranges, sm_AcceptRangesBytes);
583 }
584 
585 
587 {
589 }
590 
591 
592 void CCgiResponse::InitCORSHeaders(const string& /*origin*/,
593  const string& /*jquery_callback*/)
594 {
595  // This method is deprecated and does nothing.
596  // Use CCgiContext::ProcessCORSRequest().
597 }
598 
599 
601 {
602  CRetryContext::TValues values;
603  ctx.GetValues(values);
604  ITERATE(CRetryContext::TValues, it, values) {
605  SetHeaderValue(it->first, it->second);
606  }
607 }
608 
609 
611  eChunked_Default, // Use the hardcoded settings.
612  eChunked_Disable, // Don't use chunked encoding.
613  eChunked_Enable // Enable chunked encoding for HTTP/1.1.
614 };
615 
617 {
618  {"Disable", eChunked_Disable},
619  {"Enable", eChunked_Enable},
620 };
621 
624  eParam_NoThread, CGI_CHUNKED_TRANSFER);
625 typedef NCBI_PARAM_TYPE(CGI, ChunkedTransfer) TCGI_ChunkedTransfer;
626 
629  eParam_NoThread, CGI_CHUNK_SIZE);
630 typedef NCBI_PARAM_TYPE(CGI, ChunkSize) TCGI_ChunkSize;
631 
632 
634 {
635  return TCGI_ChunkSize::GetDefault();
636 }
637 
638 
640 {
641  // Auto-enable chunked output for HTTP/1.1.
642  const string& protocol = env.Get("SERVER_PROTOCOL");
643  return !protocol.empty() && !NStr::StartsWith(protocol, "HTTP/1.0", NStr::eNocase);
644 }
645 
646 
648 {
649  switch ( TCGI_ChunkedTransfer::GetDefault() ) {
650  case eChunked_Default:
651  if ( !m_ChunkedTransfer ) return false;
652  break;
653  case eChunked_Disable:
654  return false;
655  default:
656  break;
657  }
658  return m_Request &&
660 }
661 
662 
664 {
665  if ( m_HeaderWritten ) {
666  // Ignore attempts to enable chunked transfer if HTTP header
667  // have been written.
668  ERR_POST_X(6, "Attempt to enable chunked transfer after writing "
669  "HTTP header");
670  return;
671  }
673 }
674 
675 
677 {
678  CCgiStreamWrapper* wrapper = dynamic_cast<CCgiStreamWrapper*>(m_Output);
679  if (wrapper && wrapper->GetWriterMode() == CCgiStreamWrapper::eChunkedWrites) {
680  // Reset wrapper mode to normal if it was chunked. This will write end chunk
681  // and trailer.
683  // Block writes.
685  }
686 }
687 
688 
690 {
691  CCgiStreamWrapper* wrapper = dynamic_cast<CCgiStreamWrapper*>(m_Output);
692  if (wrapper && wrapper->GetWriterMode() == CCgiStreamWrapper::eChunkedWrites) {
693  wrapper->AbortChunkedTransfer();
694  }
695 }
696 
697 
699 {
700  if (m_HeaderWritten || !GetChunkedTransferEnabled()) return false;
701  if ( !m_TrailerEnabled.get() ) {
702  m_TrailerEnabled.reset(new bool(false));
703  const string& te = m_Request->GetRandomProperty("TE");
704  list<string> parts;
706  ITERATE(list<string>, it, parts) {
707  if (NStr::EqualNocase(*it, "trailers")) {
708  *m_TrailerEnabled = true;
709  break;
710  }
711  }
712  }
713  return *m_TrailerEnabled;
714 }
715 
716 
717 void CCgiResponse::AddTrailer(const string& name)
718 {
719  if ( !CanSendTrailer() ) return;
720  m_TrailerValues[name] = "";
721 }
722 
723 
724 void CCgiResponse::RemoveTrailer(const string& name)
725 {
726  m_TrailerValues.erase(name);
727 }
728 
729 
730 bool CCgiResponse::HaveTrailer(const string& name) const
731 {
732  return m_TrailerValues.find(name) != m_TrailerValues.end();
733 }
734 
735 
736 string CCgiResponse::GetTrailerValue(const string &name) const
737 {
739  return (ptr == m_TrailerValues.end()) ? kEmptyStr : ptr->second;
740 }
741 
742 
743 void CCgiResponse::SetTrailerValue(const string& name, const string& value)
744 {
745  if ( !HaveTrailer(name) ) {
746  ERR_POST_X(7, "Can not set trailer not announced in HTTP header: "
747  << name);
748  return;
749  }
750  if ( x_ValidateHeader(name, value) ) {
751  m_TrailerValues[name] = value;
752  }
753  else {
754  NCBI_THROW(CCgiResponseException, eBadHeaderValue,
755  "CCgiResponse::SetTrailerValue() -- "
756  "invalid trailer name or value: " +
757  name + "=" + value);
758  }
759 }
760 
761 
#define true
Definition: bool.h:35
#define false
Definition: bool.h:36
Exception classes used by the NCBI CGI framework.
API to store CGI session data between Web requests.
CCgiCookie::
Definition: ncbicgi.hpp:67
CCgiErrnoException –.
CCgiHeadException –.
CCgiRequest::
Definition: ncbicgi.hpp:685
CCgiResponseException –.
CCgiUserAgent –.
Definition: user_agent.hpp:59
CNcbiEnvironment –.
Definition: ncbienv.hpp:104
CRetryContext – Retry context.
Definition: retry_ctx.hpp:58
CTime –.
Definition: ncbitime.hpp:296
Severity –.
Definition: ncbidiag.hpp:833
void erase(iterator pos)
Definition: map.hpp:167
container_type::const_iterator const_iterator
Definition: map.hpp:53
const_iterator end() const
Definition: map.hpp:152
const_iterator lower_bound(const key_type &key) const
Definition: map.hpp:154
bool empty() const
Definition: map.hpp:149
const_iterator find(const key_type &key) const
Definition: map.hpp:153
char value[7]
Definition: config.c:431
CS_CONTEXT * ctx
Definition: t0006.c:12
static int type
Definition: getdata.c:31
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
void AbortChunkedTransfer(void)
Definition: cgiapp.cpp:446
EStreamMode GetWriterMode(void)
Definition: cgiapp.cpp:421
void SetWriterMode(EStreamMode mode)
Definition: cgiapp.cpp:427
void FinishChunkedTransfer(const TTrailer *trailer)
Definition: cgiapp.cpp:440
CGI
Definition: cgiapp.hpp:685
#define NCBI_CGI_THROW_WITH_STATUS(exception, err_code, message, status)
static string GetStdStatusMessage(EStatusCode code)
EStatusCode
HTTP status codes.
bool HaveContentRange(void) const
Check if 'Content-Range' header is set.
Definition: ncbicgir.cpp:586
static const char * sm_HTTPStatusName
Definition: ncbicgir.hpp:259
const CCgiRequest * m_Request
Definition: ncbicgir.hpp:305
unique_ptr< bool > m_TrailerEnabled
Definition: ncbicgir.hpp:307
void SetSecure(bool secure)
Definition: ncbicgi.hpp:1022
~CCgiResponse(void)
Definition: ncbicgir.cpp:105
void EndPart(void)
Definition: ncbicgir.hpp:371
static const char * sm_ContentRange
Definition: ncbicgir.hpp:265
void RemoveTrailer(const string &name)
Remove trailer. Must be called before WriteHeader().
Definition: ncbicgir.cpp:724
bool CanSendTrailer(void) const
Check if trailer can be sent: chunked transfer must be enabled and the request's TE header must inclu...
Definition: ncbicgir.cpp:698
static const char * sm_CacheControl
Definition: ncbicgir.hpp:262
void AbortChunkedTransfer(void)
Abort chunked transfer, block any writes to the output stream.
Definition: ncbicgir.cpp:689
CNcbiOstream * m_Output
Definition: ncbicgir.hpp:276
void SetHeaderValue(const string &name, const string &value)
Definition: ncbicgir.cpp:151
string GetTrailerValue(const string &name) const
Get current trailer value.
Definition: ncbicgir.cpp:736
unique_ptr< CCgiCookie > m_TrackingCookie
Definition: ncbicgir.hpp:294
void SetChunkedTransferEnabled(bool value)
Definition: ncbicgir.cpp:663
void x_RestoreOutputExceptions(void)
Definition: ncbicgir.cpp:215
static const char * sm_AcceptRanges
Definition: ncbicgir.hpp:263
CCgiRequest::ERequestMethod m_RequestMethod
Definition: ncbicgir.hpp:281
void SetThrowOnBadOutput(bool throw_on_bad_output)
If set to TRUE then the writes to a "bad" output stream will throw exceptions of type std::ios_base::...
Definition: ncbicgir.cpp:563
static const char * sm_ContentTypeMixed
Definition: ncbicgir.hpp:254
static const char * sm_ContentTypeDefault
Definition: ncbicgir.hpp:253
string m_JQuery_Callback
Definition: ncbicgir.hpp:312
void Flush(void) const
Flush output stream.
Definition: ncbicgir.cpp:529
bool m_RequireWriteHeader
Definition: ncbicgir.hpp:279
string m_Boundary
Definition: ncbicgir.hpp:272
void SetExceptionAfterHEAD(bool expt_after_head)
Definition: ncbicgir.cpp:573
static const char * sm_FilenamePrefix
Definition: ncbicgir.hpp:258
static const char * sm_ContentTypeName
Definition: ncbicgir.hpp:251
CNcbiOstream::iostate m_OutputExpt
Definition: ncbicgir.hpp:280
CNcbiOstream & out(void) const
Get output stream. Throw exception if GetOutput() is NULL.
Definition: ncbicgir.cpp:257
TMap m_TrailerValues
Definition: ncbicgir.hpp:274
void AddTrailer(const string &name)
Prepare to send trailer.
Definition: ncbicgir.cpp:717
static const char * sm_ContentTypeRelated
Definition: ncbicgir.hpp:255
void SetFilename(const string &name, size_t size=0)
Definition: ncbicgir.cpp:470
static const char * sm_ContentDispoName
Definition: ncbicgir.hpp:257
void SetStatus(unsigned int code, const string &reason=kEmptyStr)
Definition: ncbicgir.cpp:197
EMultipartMode m_IsMultipart
Definition: ncbicgir.hpp:270
CCgiResponse(CNcbiOstream *os=NULL, int ofd=-1)
Definition: ncbicgir.cpp:85
bool m_ChunkedTransfer
Definition: ncbicgir.hpp:306
void SetTrackingCookie(const string &name, const string &value, const string &domain, const string &path, const CTime &exp_time=CTime())
Definition: ncbicgir.cpp:539
const CNcbiEnvironment & GetEnvironment() const
Definition: ncbicgi.hpp:891
static bool x_ClientSupportsChunkedTransfer(const CNcbiEnvironment &env)
Definition: ncbicgir.cpp:639
void SetOutput(CNcbiOstream *os, int fd=-1)
Set output stream (NULL here means "no output stream").
Definition: ncbicgir.cpp:223
void SetHttpOnly(bool http_only)
Definition: ncbicgi.hpp:1025
bool m_DisableTrackingCookie
Definition: ncbicgir.hpp:295
static const char * sm_HTTPStatusDefault
Definition: ncbicgir.hpp:260
CCgiCookie * Add(const string &name, const string &value, const string &domain=kEmptyStr, const string &path=kEmptyStr, EOnBadCookie on_bad_cookie=eOnBadCookie_SkipAndError)
All Add() functions: if the added cookie has the same {name, domain, path} as an already existing one...
Definition: ncbicgi.cpp:383
CCgiCookies m_Cookies
Definition: ncbicgir.hpp:275
static size_t GetChunkSize(void)
Definition: ncbicgir.cpp:633
void Finalize(void) const
Called by the CGI framework after a ProcessRequest(), unless the latter threw an exception.
Definition: ncbicgir.cpp:458
bool HaveTrailer(const string &name) const
Check if trailer has been added and its value can be set.
Definition: ncbicgir.cpp:730
static const char * sm_LocationName
Definition: ncbicgir.hpp:252
TMap m_HeaderValues
Definition: ncbicgir.hpp:273
void EndLastPart(void)
Definition: ncbicgir.hpp:376
bool AcceptRangesBytes(void) const
Check if 'Accept-Ranges' header is set to 'bytes'.
Definition: ncbicgir.cpp:579
string GetHeaderValue(const string &name) const
Definition: ncbicgir.cpp:117
const string & GetRandomProperty(const string &key, bool http=true) const
Get value of a random client property; if "http" is TRUE then add prefix "HTTP_" to the property name...
Definition: ncbicgi.cpp:1438
void SetRetryContext(const CRetryContext &ctx)
Set retry headers from the context.
Definition: ncbicgir.cpp:600
bool HaveHeaderValue(const string &name) const
Definition: ncbicgir.cpp:111
bool x_ValidateHeader(const string &name, const string &value) const
Definition: ncbicgir.cpp:131
bool GetAllCookiesSecure(void) const
Definition: ncbicgi.hpp:324
void SetTrailerValue(const string &name, const string &value)
Set trailer value.
Definition: ncbicgir.cpp:743
void FinishChunkedTransfer(void)
Finish chunked transfer, append zero chunk and trailers, if any.
Definition: ncbicgir.cpp:676
CNcbiOstream & WriteHeader(void) const
Write HTTP response header to the output stream.
Definition: ncbicgir.hpp:396
bool IsRawCgi(void) const
Definition: ncbicgir.hpp:332
void InitCORSHeaders(const string &origin, const string &jquery_callback=kEmptyStr)
This method is called automatically by CCgiContext.
Definition: ncbicgir.cpp:592
bool GetAllCookiesHttpOnly(void) const
Definition: ncbicgi.hpp:328
void RemoveHeaderValue(const string &name)
Definition: ncbicgir.cpp:125
static const char * sm_AcceptRangesBytes
Definition: ncbicgir.hpp:264
const CCgiSession * m_Session
Definition: ncbicgir.hpp:293
CNcbiOstream * GetOutput(void) const
Get output stream (NULL here means "no output stream").
Definition: ncbicgir.cpp:239
static const char * sm_ContentTypeXMR
Definition: ncbicgir.hpp:256
TCGI_ThrowOnBadOutput m_ThrowOnBadOutput
Definition: ncbicgir.hpp:299
bool GetChunkedTransferEnabled(void) const
Check/change chunked transfer encoding status.
Definition: ncbicgir.cpp:647
bool m_BetweenParts
Definition: ncbicgir.hpp:271
bool Empty(void) const
Return TRUE if this set contains no cookies.
Definition: ncbicgi.hpp:1112
static const char * sm_BoundaryPrefix
Definition: ncbicgir.hpp:261
bool m_HeaderWritten
Definition: ncbicgir.hpp:278
void BeginPart(const string &name, const string &type, size_t size=0)
Definition: ncbicgir.hpp:365
void DisableTrackingCookie(void)
Definition: ncbicgir.cpp:557
TCGI_ExceptionAfterHEAD m_ExceptionAfterHEAD
Definition: ncbicgir.hpp:303
@ eMultipart_related
Definition: ncbicgir.hpp:102
@ eMultipart_replace
Definition: ncbicgir.hpp:103
const CCgiCookie * GetSessionCookie(void) const
Get a cookie pertaining to the session.
@ eEngine_IE
Microsoft Internet Explorer (Trident and etc)
Definition: user_agent.hpp:193
#define NULL
Definition: ncbistd.hpp:225
int GetRequestStatus(void) const
Request exit status.
CDiagContext & GetDiagContext(void)
Get diag context instance.
Definition: logging.cpp:818
const string & GetNextSubHitID(CTempString prefix=CTempString())
Get current hit id appended with auto-incremented sub-hit id.
#define ERR_POST_X_ONCE(err_subcode, message)
Error posting only once during program execution with default error code and given error subcode.
Definition: ncbidiag.hpp:621
static CRequestContext & GetRequestContext(void)
Shortcut to CDiagContextThreadData::GetThreadData().GetRequestContext()
Definition: ncbidiag.cpp:1901
void SetRequestStatus(int status)
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
#define THROW1_TRACE(exception_class, exception_arg)
Throw trace.
Definition: ncbiexpt.hpp:417
@ eParam_NoThread
Do not use per-thread values.
Definition: ncbi_param.hpp:418
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
string Printable(char c)
Convert one single character to a "printable" form.
Definition: ncbistre.cpp:505
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
#define NcbiCout
Definition: ncbistre.hpp:543
#define NcbiFlush
Definition: ncbistre.hpp:550
static string SizetToString(size_t value, TNumToStringFlags flags=0, int base=10)
Convert size_t to string.
Definition: ncbistr.cpp:2751
static string PrintableString(const CTempString str, TPrintableMode mode=fNewLine_Quote|fNonAscii_Passthru)
Get a printable version of the specified string.
Definition: ncbistr.cpp:3949
#define kEmptyStr
Definition: ncbistr.hpp:123
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3457
static SIZE_TYPE FindNoCase(const CTempString str, const CTempString pattern, SIZE_TYPE start, SIZE_TYPE end, EOccurrence which=eFirst)
Find the pattern in the specified range of a string using a case insensitive search.
Definition: ncbistr.cpp:2989
#define NPOS
Definition: ncbistr.hpp:133
static string UIntToString(unsigned int value, TNumToStringFlags flags=0, int base=10)
Convert UInt to string.
Definition: ncbistr.hpp:5108
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5411
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5352
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3401
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3182
@ fSplit_Truncate
Definition: ncbistr.hpp:2501
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2498
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
string AsString(const CTimeFormat &format=kEmptyStr, TSeconds out_tz=eCurrentTimeZone) const
Transform time to string.
Definition: ncbitime.cpp:1511
bool IsEmpty(void) const
Is time object empty (date and time)?
Definition: ncbitime.hpp:2378
CTime & AddYear(int years=1, EDaylight adl=eDaylightDefault)
Add specified years and adjust for daylight saving time.
Definition: ncbitime.hpp:2293
CTime GetGmtTime(void) const
Definition: ncbitime.hpp:1156
@ eCurrent
Use current time. See also CCurrentTime.
Definition: ncbitime.hpp:300
@ eGmt
GMT (Greenwich Mean Time)
Definition: ncbitime.hpp:308
Definition of all error codes used in cgi (xcgi.lib).
pair< int, int > ChunkSize(const CSpliced_exon_chunk &chunk)
int i
const struct ncbi::grid::netcache::search::fields::SIZE size
Static variables safety - create on demand, destroy on application termination.
static const tm kZeroTime
Definition: ncbicgi.cpp:138
NCBI_PARAM_DEF_EX(size_t, CGI, ChunkSize, 4096, eParam_NoThread, CGI_CHUNK_SIZE)
NCBI_PARAM_ENUM_ARRAY(ECgiChunkedTransfer, CGI, ChunkedTransfer)
Definition: ncbicgir.cpp:616
typedef NCBI_PARAM_TYPE(CGI, ChunkedTransfer) TCGI_ChunkedTransfer
NCBI_PARAM_DEF_IN_SCOPE(bool, CGI, ThrowOnBadOutput, true, CCgiResponse)
NCBI_PARAM_DECL(size_t, CGI, ChunkSize)
NCBI_PARAM_ENUM_DEF_EX(ECgiChunkedTransfer, CGI, ChunkedTransfer, eChunked_Default, eParam_NoThread, CGI_CHUNKED_TRANSFER)
#define STDOUT_FILENO
Definition: ncbicgir.cpp:48
ECgiChunkedTransfer
Definition: ncbicgir.cpp:610
@ eChunked_Enable
Definition: ncbicgir.cpp:613
@ eChunked_Disable
Definition: ncbicgir.cpp:612
@ eChunked_Default
Definition: ncbicgir.cpp:611
NCBI_PARAM_ENUM_DECL(ECgiChunkedTransfer, CGI, ChunkedTransfer)
bool s_ZeroTime(const tm &date)
Definition: ncbicgir.cpp:78
#define HTTP_EOL
Definition: ncbistre.hpp:120
static SQLCHAR output[256]
Definition: print.c:5
Defines CRequestContext class for NCBI C++ diagnostic API.
Definition: inftrees.h:24
Definition: type.c:6
static int failure
Definition: t0019.c:11
#define _ASSERT
static HENV env
Definition: transaction2.c:38
Modified on Sat Dec 09 04:47:35 2023 by modify_doxy.py rev. 669887