Compare commits

..

181 Commits

Author SHA1 Message Date
Nik Bougalis
a5d5856638 Set version to 0.31.0 2016-04-18 14:23:18 -07:00
Nik Bougalis
4e64e3f1dd Check file handle limit on startup (RIPD-442, RIPD-1024):
Calculate the number of file descriptors that are needed during
execution based on the configuration file, with a hard floor
of 1024, adjusting the limit if possible. Refuse to run if enough
fds are not available.

Additionally, allow administrators to limit the number of incoming
connections a configured port will accept. By default no limit is
imposed.
2016-04-18 14:23:18 -07:00
Nik Bougalis
51850ded05 Improve watchdog start logic 2016-04-18 14:23:17 -07:00
Miguel Portilla
76d7c1c01a Fix secured Websocket closing.
Websocketpp was incorrectly handling close before or during protocol negotiation. This issue addresses lingering CLOSE_WAIT file descriptors.
2016-04-18 14:23:00 -07:00
David Schwartz
dabc5567f7 Small Websocket cleanups. 2016-04-18 14:23:00 -07:00
Nik Bougalis
5c5ee6f763 Set version to 0.31.0-rc2 2016-04-01 14:32:00 -07:00
Nik Bougalis
06bfcad671 Validate the tx_json field in sign_for (RIPD-1100) 2016-04-01 14:31:40 -07:00
Nik Bougalis
73e48e6595 Only object instances can have members (RIPD-1100) 2016-04-01 14:31:34 -07:00
Miguel Portilla
906ef761ba Set version to 0.31.0-rc1 2016-03-15 15:12:35 -04:00
Miguel Portilla
6b87a67592 Merge remote-tracking branch 'upstream/release' into develop 2016-03-15 15:10:05 -04:00
Edward Hennis
e16361826e Set version to 0.31.0-b14 2016-03-10 15:02:04 -05:00
Edward Hennis
a327cecee6 Create new Validations columns properly:
* Thread-safe preparation of Validations cleanup query
* Followup to RIPD-870
2016-03-10 14:57:59 -05:00
Vinnie Falco
64d9f7c23e Set version to 0.31.0-b13 2016-03-09 17:48:58 -05:00
Vinnie Falco
4f16a1cee9 Disable SHAMapStore test:
The test depends on an asynchronous operation completing
in a certain time, failing periodically due to timing.
2016-03-09 17:47:37 -05:00
Miguel Portilla
8f83f69325 RPC robust transaction unit test (RIPD-1079) 2016-03-09 16:23:26 -05:00
Miguel Portilla
1d0ca51c88 RPC book unit test (RIPD-1077) 2016-03-09 16:23:25 -05:00
Miguel Portilla
ca70f4fab1 RPC subscribe unit test (RIPD-1076) 2016-03-09 16:23:25 -05:00
Miguel Portilla
72cdf3f555 Improve held transaction submission:
Removed redundant validity checks for held transactions in NetworkOPsImp::apply.
2016-03-09 16:23:24 -05:00
Miguel Portilla
1c68fddad7 Subscribe cleanup 2016-03-09 16:23:24 -05:00
Miguel Portilla
2f3b5f6d0a Log websocket received messages 2016-03-09 16:23:24 -05:00
Miguel Portilla
5663c45a0d Add jtx::json string constructor 2016-03-09 16:23:23 -05:00
Miguel Portilla
172356d299 Add JobCoro destructor completion assert
Make JobCoro non copyable
2016-03-09 16:23:23 -05:00
Vinnie Falco
2323ea4493 Add WSClient 2016-03-09 16:23:23 -05:00
Vinnie Falco
d6a666f4e0 Add wsproto 2016-03-09 16:23:22 -05:00
Vinnie Falco
6e70a6c6f5 Remove 'skip on stop' job attribute 2016-03-09 16:23:22 -05:00
Vinnie Falco
b82be0a9b0 Skip websocket commands on stop 2016-03-09 16:23:22 -05:00
Vinnie Falco
94a47569d6 Check suspended coros for JobQueue stop condition 2016-03-09 16:23:21 -05:00
Vinnie Falco
73df97f2d0 Add JobQueue::rendezvous 2016-03-09 16:23:21 -05:00
Vinnie Falco
e8b75b80c2 Remove obsolete JobQueue thread tracking 2016-03-09 16:23:21 -05:00
Vinnie Falco
9ab5611c65 Fix destructor race in Job 2016-03-09 16:23:20 -05:00
Vinnie Falco
92391332d7 Reduce the runtime of nudb.recover test 2016-03-09 16:23:20 -05:00
Vinnie Falco
8e26b187be Set TCP_NODELAY on plain, loopback JSONRPC clients 2016-03-09 16:23:20 -05:00
Vinnie Falco
79ce5901f3 Improved write buffering in JSONRPC client 2016-03-09 16:23:19 -05:00
Vinnie Falco
29a4849024 Improve socket writes in BaseHTTPPeer 2016-03-09 16:23:19 -05:00
Nik Bougalis
0a1731c4c9 Assign non-default Rules correctly 2016-03-09 13:48:12 -05:00
Nik Bougalis
5cac2befb0 Avoid deriving a known PublicKey 2016-03-09 13:32:16 -05:00
Vinnie Falco
e6d4436e9d Update parser for http-parser:
* Remove unused raw_parser
* C++ parser wrapper is updated
2016-03-08 12:01:41 -05:00
Vinnie Falco
16b1adfa86 Update http-parser subtree:
Source: https://github.com/nodejs/http-parser/commits/master
Commit: fd65b0fbbdb405425a14d0e49f5366667550b1c2
Merge commit '404d58d77c3ecbea68e0bd4fa1e7ff4b7c000fc5' into parser
2016-03-04 12:27:24 -05:00
Vinnie Falco
404d58d77c Squashed 'src/beast/beast/http/impl/http-parser/' changes from cba704c..fd65b0f
fd65b0f src: refactor method parsing
678a9e2 test: Assert against correct error messages
e2e467b Update http-parser to 2.6.1
4e382f9 readme: fix build status badge
bee4817 Bump version to 2.6.0
777ba4e src: introduce `http_parser_url_init`
483eca7 doc: updated README.md to include multi-threading example
e557b62 src: support LINK/UNLINK (RFC 2068, draft-snell-link-method)
e01811e src: fixed compile error C2143 for vs2012
b36c2a9 header: treat Wine like MinGW
eb5e992 src: support ACL (WebDAV, RFC3744, Section 8.1).
4f69be2 readme: update WebSocket link to RFC6455
b5bcca8 test: `SEARCH`, `PURGE` and `MKCALENDAR`
8b1d652 src: support BIND/REBIND/UNBIND (WebDAV, RFC5842)
7d75dd7 src: support IPv6 Zone ID as per RFC 6874
ab0b162 src: use ARRAY_SIZE instead of sizeof()
39ff097 src: remove double check
f6f436a src: fix invalid memory access in http_parse_host
2896229 make: fix dynamic library extension for OS X
39c2c1e Bump version to 2.5.0
dff604d src: support body in Upgrade requests
d767545 src: callbacks chunk boundaries: header/complete
2872cb7 test: regression test for incomplete/corrupted hdr
5d414fc makefile: add un/install targets
d547f3b url_parser: remove mixed declarations
7ecf775 src: partially revert 959f4cb to fix nread value
7ba3123 header: fix field sizes
53063b7 Add function to initialize http_parser_settings
1b31580 Bump version to 2.4.2
59569f2 src: skip lws between `connection` values
36f107f Bump version to 2.4.1
280af69 src: fix build on MSVC
956c8a0 Bump version to 2.4.0
167dcdf readme: fix typo
3f7ef50 src: annotate with likely/unlikely
265f9d0 bench: add chunked bytes
091ebb8 src: simple Connection header multi-value parsing
959f4cb src: remove reexecute goto
0097de5 src: use memchr() in h_general header value
c6097e1 src: faster general header value loop
2630060 src: less loads in header_value loop
0cb0ee6 src: tighten header field/value loops
6132d1f src: save progress
3f1a05a benchmark: initial
94a55d1 send travis irc notifications to #node-ci
5fd51fd Fix warning on test suite found by Clang Analyzer
0b43367 http_parser: Follow RFC-7230 Sec 3.2.4
11ecb42 Docs fix
7bbb774 doc: add very basic docs for `http_parser_execute`
17ed7de header: typo fix in a comment
5b951d7 src: fix clang warning
1317eec Added support for MKCALENDAR
08a2cc3 very minor spelling/grammar changes in README.md
158dd3b signing the CLA is no longer a requirement
8d9e5db fix typo in README comment
d19e129 contrib: fixed resource leak in parsertrace
24e2d2d Allow HTTP_MAX_HEADER_SIZE to be defined externally
56f7ad0 Bump version to 2.3.0
76f0f16 Fix issues around multi-line headers
5d9c382 Include separating ws when folding header values

git-subtree-dir: src/beast/beast/http/impl/http-parser
git-subtree-split: fd65b0fbbdb405425a14d0e49f5366667550b1c2
2016-03-04 12:26:41 -05:00
Nik Bougalis
6c712ff2df Set version to 0.31.0-b12 2016-03-03 13:16:06 -08:00
Scott Schurr
308aaa6f78 Test how beast::is_call_possible<> handles const-ness. 2016-03-03 13:16:02 -08:00
Edward Hennis
eb62959216 Clear old Validations during online delete (RIPD-870):
* Add Validations.LedgerSeq and .InitialSeq fields.
* Clean up logging.
* Lower online delete minimum for standalone mode.
* Unit tests of online_delete.
2016-03-03 13:16:02 -08:00
JoelKatz
70d5c4eca7 Avoid passing SHAMapNodeID's to sync filters 2016-03-03 13:10:28 -08:00
Nik Bougalis
a025d365b8 Verify that returned RPC codes are known 2016-03-03 13:05:11 -08:00
Nik Bougalis
89fa10b40b Add description of rpcSENDMAX_MALFORMED error 2016-03-03 13:05:04 -08:00
Nik Bougalis
34e85ccb62 Refactor treatment of Ledger:
All handling of Ledger in shared_ptr is modified to
use a const managed object when the context requires
immutable semantics.
2016-03-03 13:02:13 -08:00
Nik Bougalis
77a4218a9e Set version to 0.31.0-b11 2016-02-29 13:46:37 -05:00
seelabs
d8ee487c19 Fix underflow issue for XRP:
In some cases multiplying or dividing STAmounts gave incorrect results.

This happens when:

1) The result should be rounded up
2) The STAmount represents a native value (XRP)
3) The rounded up value was less than one drop

In this case, the result was zero, instead of one drop. This could
cause funded offers to be removed as unfunded.
2016-02-29 13:42:55 -05:00
seelabs
3605bf1f60 Chrono fixes for VS Update 2 2016-02-29 13:42:55 -05:00
Nik Bougalis
d3b43bfa37 Report slow stop times only in release builds 2016-02-29 13:42:55 -05:00
Nik Bougalis
bf6079797f Simplify logging:
* Construct Logs with the correct severity
* Remove deprecatedLogs and log squelching support
* Use debugJournal for AutoSocket logging
2016-02-29 13:42:55 -05:00
Scott Schurr
6366f62f11 Cleanups in beast::Journal:
The Journal API is affected.  There are two uses for the
Journal::Severity enum:

 o It is used to declare a threshold which log messages must meet
   in order to be logged.

 o It declares the current logging level which will be compared
   to the threshold.

Those uses that affect the threshold are now named threshold()
rather than severity() to make the uses easier to distinguish.

Additionally, Journal no longer carries a Severity variable.
All handling of the threshold() is now delegated to the
Journal::Sink.

Sinks are no longer constructed with a default threshold of
kWarning; their threshold must be passed in on construction.
2016-02-29 13:42:55 -05:00
Nik Bougalis
427c33dbd7 Set version to 0.30.1-hf2 2016-02-26 15:58:09 -08:00
seelabs
675cbb72a6 Fix underflow issue for XRP:
When specifying that a result should be rounded up,
the code rounded up to a value suitable for a non-xrp
amount. When called with an xrp amount, if that rounded-up
value was less than one drop, the code rounded down to zero.

This could cause funded offers to be removed as unfunded.
2016-02-26 15:57:39 -08:00
Vinnie Falco
f846b1a88f Set version to 0.31.0-b10 2016-02-25 13:57:10 -05:00
Vinnie Falco
4bfcd12897 Disable Rules assignment in Ledger::setup:
This is a temporary fix for a thread-unsafe access.
2016-02-25 13:57:04 -05:00
Nik Bougalis
d736232142 Pathfinding cleanup:
* Remove unused code
* Do not use `pointer` and `ref` type aliases
* Misc. cleanups
2016-02-25 13:38:46 -05:00
Scott Schurr
9cb02028ed Increase JLOG usage. 2016-02-25 13:38:45 -05:00
Scott Schurr
0703441ee7 Extend View.cpp unit test coverage. 2016-02-25 13:34:58 -05:00
Vinnie Falco
2c3128d9ba Ignore error on socket shutdown 2016-02-25 13:34:57 -05:00
Vinnie Falco
7837eed21b Disable Rules assignment in Ledger::setup:
This is a temporary fix for a thread-unsafe access.
2016-02-22 14:40:44 -05:00
Nik Bougalis
db092449f9 Set version to 0.31.0-b9 2016-02-18 13:54:15 -08:00
Nik Bougalis
d321b446db Remove tracking by public key in Overlay 2016-02-18 13:54:10 -08:00
Nik Bougalis
78ce7a08c0 Return correct error code during unfunded offer cross (RIPD-1082):
When placing an offer that sells XRP, if the account's balance was
low enough that paying the transaction fee would drop the balance
below the reserve, the transaction should return tecUNFUNDED_OFFER.

The existing implementation returned a tesSUCCESS instead. Although
the net result is the same as far as the transaction's effects are
concerned (the offer is not placed on the books and the transaction
fee is charged) the incorrect result code makes deciphering metadata
difficult.

Add unit test that verifies the new behavior.
2016-02-18 13:54:10 -08:00
Nik Bougalis
15adb73a13 Unit tests for offer creation:
* Test whether offers which either already below the reserve (or
  would go below during processing) can execute if they cross.
* Test the "Fill or Kill" and "Immediate or Cancel" flags.
2016-02-18 13:54:10 -08:00
Scott Schurr
f15cc6c4f6 Document feature RPC command in --help. 2016-02-17 16:33:02 -08:00
seelabs
61e6e5694c Add virtual destructor to Logs 2016-02-17 16:33:02 -08:00
Edward Hennis
66bc0bb424 Copy rules from parent ledger 2016-02-17 16:33:02 -08:00
David Schwartz
25589bacea Ensure fee change transactions have a unique transaction ID
Include the ledger sequence number in fee change transactions to ensure
each such transaction has a unique transaction ID.

We tolerate the absence of a ledger sequence in fee change transactions so
that past fee change transactions remain parseable. Since no live amendment
transactions have yet happened, there is no need to tolerate an absent
ledger sequence there.
2016-02-17 16:33:02 -08:00
JoelKatz
d721d35a2d Update SQLite from 3.8.11.1 to 3.11.0 2016-02-17 16:29:00 -08:00
Vinnie Falco
ba84fc2c77 Set version to 0.31.0-b8 2016-02-11 18:43:06 -05:00
Vinnie Falco
0f7dbc7bc0 Fix Server race conditions:
Class io_list manages children that perform asynchronous
I/O operations. The treatment of close and destruction is
refactored to fix race conditions during exit.
2016-02-11 18:42:34 -05:00
Vinnie Falco
137dd351b8 Refactor Server:
* Remove HTTP namespace
* Rename connection classes
* Mark Server test automatic
* Build server sources in classic
2016-02-11 18:42:33 -05:00
Vinnie Falco
ba38bfad9d Server deadlock fixes 2016-02-11 18:42:33 -05:00
Vinnie Falco
be71e8afa2 Get X-Forwarded-For from Session request 2016-02-11 18:42:33 -05:00
Vinnie Falco
de416adadd Disable WebSocket logging 2016-02-11 18:42:32 -05:00
Vinnie Falco
1fda99ba82 Add suite::this_suite 2016-02-11 18:42:32 -05:00
Vinnie Falco
9f5b58c8ab Fix short_read test race/deadlock 2016-02-11 18:42:31 -05:00
Vinnie Falco
8c11d24454 Reinforce Env Application log severity 2016-02-11 18:42:30 -05:00
Vinnie Falco
924b6b663e Increase severity on Stoppable logging 2016-02-11 18:42:30 -05:00
Nik Bougalis
688452d971 Fix OptionalProxy<T> equality comparison 2016-02-11 18:41:42 -05:00
Scott Schurr
2f94e16359 Add SignerList to account_info response (RIPD-1061):
The caller of the account_info RPC command can optionally
specify that they want the account's SignerList returned by
adding the argument:

"signer_lists": "true"

The returned SignerList is in an array.  This leaves us room to
support multiple signer lists on an account in the future without
changing the syntax of the result.

The command-line version of account_info does not support the new
option.
2016-02-11 18:41:03 -05:00
Miguel Portilla
fbf736f169 Improved reporting for delivered_amount:
* Determine tx success from metadata result.
* Report delivered_amount for legacy account_tx queries.
2016-02-11 18:39:12 -05:00
Vinnie Falco
f0624581d1 Set version to 0.30.1-hf1 2016-02-11 18:19:31 -05:00
Vinnie Falco
cb23352a35 Revert "Set version to 0.30.1-hf1"
This reverts commit 9fea06ad84.
2016-02-11 18:19:08 -05:00
Vinnie Falco
9fea06ad84 Set version to 0.30.1-hf1 2016-02-11 15:48:32 -05:00
Miguel Portilla
2beeb9a293 Improved reporting for delivered_amount:
* Determine tx success from metadata result.
* Report delivered_amount for legacy account_tx queries.
2016-02-11 15:47:40 -05:00
Nik Bougalis
1e92ac3cf5 Set version to 0.31.0-b7 2016-02-08 15:50:12 -08:00
Scott Schurr
acaf91a2f7 Add AccountLinesRPC unit tests. 2016-02-08 15:50:02 -08:00
seelabs
41125a0a34 Support for clang specific boost and protobuf dirs:
Clang does not understand gcc 5's new ABI. On linux systems
that default to the new ABI (such as ubuntu 15.10), building
with clang requires using C++ libraries built with the the old
gcc ABI.

When building with the clang protobuf lib, a common error is to
load the gcc protobuf library at run time. When set, PROTOBUF_ROOT
is added to rpath to make sure the correct lib is loaded.

Adds a script to install clang and download and build boost and
protobuf with boost.
2016-02-08 15:50:02 -08:00
Nik Bougalis
35ed095dbf Cleanup ledger fetching 2016-02-08 15:50:02 -08:00
Nik Bougalis
ce31e26f58 Enable amendment support 2016-02-08 15:47:57 -08:00
Nik Bougalis
2b640532f2 Merge remote-tracking branch 'upstream/release' into develop 2016-02-08 15:45:10 -08:00
Nik Bougalis
c717006c44 Set version to 0.30.1 2016-02-08 15:37:02 -08:00
Nik Bougalis
fd33d693c4 Merge remote-tracking branch 'upstream/master' 2016-02-08 15:36:04 -08:00
Nik Bougalis
31ecb4dcf3 Revert "Set version to 0.30.1"
This reverts commit 5a4e900a21.
2016-02-08 15:35:22 -08:00
Nik Bougalis
5a4e900a21 Set version to 0.30.1 2016-02-03 14:49:07 -08:00
Nik Bougalis
94ed5b3a53 Set version to 0.31.0-b6 2016-02-01 21:07:52 -08:00
Scott Schurr
2eaf211e9b Improve error message when signing fails (RIPD-1066):
With the addition of multisigning there are a variety of reasons
a signature may fail.  We now return a more descriptive message
for the reason certain signature checks fail.
2016-02-01 21:07:41 -08:00
Miguel Portilla
ed9f5639a8 Throws, explicits and trivial cleanups 2016-02-01 21:07:41 -08:00
Edward Hennis
8e842b5893 Disable tx sig checking at the Application level:
* Only skip sig checking on the RPC/Websocket interface.
* Used by Env tests which submit unsigned transactions.
2016-02-01 21:07:41 -08:00
JoelKatz
1b378172b6 Clean up some consensus edge cases:
* Ensure sufficient time for proposals before increasing avalanche threshold
* Only validators should count themselves towards 80% needed for consensus
2016-02-01 21:07:41 -08:00
Markus Teufelberger
0dc911c091 Do not show progess bar on npm install on CI
See https://github.com/npm/npm/issues/11283 for more discussion on this.
2016-02-01 21:07:41 -08:00
Vinnie Falco
2be11874e3 Improved unit test logging:
Logging from the Application object in the Env is
redirected to the suite::log, with the severity level
set to error and above.
2016-02-01 21:07:41 -08:00
Nik Bougalis
5ac744ff66 Implement a debug Journal 2016-02-01 21:06:56 -08:00
Nik Bougalis
57d6ab091c Cleanups:
* Use Throw instead of directly throwing an exception
2016-02-01 21:06:56 -08:00
Nik Bougalis
f13668371e Amendment RPC enhancements:
* RPC command to veto/unveto
* Store votes
* Add vote information to JSON
* Add ledger majority information to JSON
* Config section for vetos
2016-02-01 21:06:56 -08:00
Nik Bougalis
c9486863c3 Set version to 0.31.0-b5 2016-01-28 12:05:08 -08:00
Nik Bougalis
e9e0277b7c Improve manifest loading 2016-01-28 12:05:00 -08:00
Miguel Portilla
b69f0356ec Convert PathRequest to use std::chrono (RIPD-1069) 2016-01-28 12:05:00 -08:00
Edward Hennis
4d72fc225a Unit test of RPC ledger_request 2016-01-28 12:04:58 -08:00
Edward Hennis
9786e432f8 ledger_request index must be positive 2016-01-28 12:04:57 -08:00
Vinnie Falco
040d7ebb46 Refactor Env for AbstractClient:
Env is changed to use the AbstractClient interface,
which generalizes the transport for submitting client
requests to the Env server instance.

The JSONRPCClient implementation is added, supporting
a simple, synchronous interface. Env is changed to
use the JSONRPCClient implementation instead of the
built in JSON-RPC client.
2016-01-28 12:04:57 -08:00
Scott Schurr
f9f2b8124d Add cmdLineToJSONRPC (RIPD-1074) 2016-01-28 12:04:55 -08:00
Vinnie Falco
dd5d938aa3 Make ParsedPort public 2016-01-28 12:04:55 -08:00
Edward Hennis
7c82adcc84 Avoid missing node errors on genesis ledger creation 2016-01-28 12:04:53 -08:00
Howard Hinnant
bdb1966573 Remove lvalue overload of SHAMap::addItem:
This overload was mistakenly used, but not needed
in the Ledger logic.  Removing this overload turns
this performance bug into a compile time error.
2016-01-28 09:39:30 -08:00
Howard Hinnant
a1582c610e Consolidate getStack into walkTowardsKey:
*  This removes duplicate functionality.
2016-01-28 09:39:30 -08:00
Howard Hinnant
2f9f217c11 Remove NodeStack:
*  This gets all parts of SHAMap using a single type of stack.
*  This paves the way for more code sharing.
2016-01-28 09:39:30 -08:00
seelabs
278f679bb1 Enable underflow fix after specified date 2016-01-28 09:39:30 -08:00
seelabs
96bc727fcb Enforce no-ripple constraints 2016-01-27 17:05:31 -05:00
seelabs
7d2809eb27 Unit test for enforcing no ripple 2016-01-27 17:05:31 -05:00
Nik Bougalis
5062e65277 Set version to 0.30.1-rc4 2016-01-27 13:33:07 -08:00
seelabs
bd44880d5a Enforce no-ripple constraints 2016-01-27 13:32:38 -08:00
Nik Bougalis
ad2383bd4b Set version to 0.30.0-hf2 2016-01-27 12:27:27 -08:00
Nik Bougalis
5b5a01989c Improve compile-time OpenSSL version check 2016-01-27 12:27:18 -08:00
seelabs
c17f7e8b37 Enforce no-ripple constraints 2016-01-26 13:52:41 -08:00
Nik Bougalis
9b8133f65f Set version to 0.31.0-b4 2016-01-25 10:35:56 -08:00
Vinnie Falco
77c0236cae Serialize Application start up:
These changes ensure the caller can block until the
Application object can be fully prepared (especially
listening sockets). Solves the problem where tests
can attempt connections before the server sockets are
ready.

* WebSocket blocks until listening
* Application setup blocks until prepared and started
2016-01-25 10:35:54 -08:00
seelabs
07c4262392 Fix websocket deadlock:
A copy of the connection list is made on stop so it
can be iterated without holding the endpoint lock.
2016-01-25 10:35:54 -08:00
Vinnie Falco
10a5421987 Remove unused websocket04 2016-01-25 10:35:54 -08:00
Scott Schurr
48f0e1f51d CBigNum unit tests 2016-01-25 10:35:53 -08:00
Scott Schurr
9063953ee7 Convert fast manual unit tests to automatic 2016-01-25 10:35:53 -08:00
seelabs
7315d9c300 Do not destroy objects until all threads exit in Stoppable test
Objects of class `A` could be destroyed before all their member
functions finished running.
2016-01-25 10:35:53 -08:00
wilsonianb
05c248f297 Include ledger_index in validations subscription stream 2016-01-25 10:35:53 -08:00
wilsonianb
b92a58d11e Allow random seed with specified wallet_propose key_type (RIPD-1030) 2016-01-25 10:35:53 -08:00
Nik Bougalis
767d253593 Improve manifest public key loading 2016-01-25 10:35:53 -08:00
Nik Bougalis
78e59191ed Add unit tests for Endpoint string parsing 2016-01-25 09:07:41 -08:00
Nik Bougalis
de4d872b7a Simplify Beast:
* Remove asio HTTP classes
 * Remove beast::File, beast::String, beast::Stream, beast::Array,
   beast::MemoryBlock, beast::CriticalSection and other unused
   classes.
 * Remove unused platform-specific code.
 * Reduce Beast custom assert and debugging helper macros.
2016-01-25 09:07:41 -08:00
Nik Bougalis
77955c74bc Use boost::filesystem instead of beast::File 2016-01-25 09:07:41 -08:00
Nik Bougalis
555cd59a59 Cleanups:
* Reduce Beast dependencies
* Remove unnecessary includes
* Don't use deprecated bassert macros
* Don't use beast::String in Json::Value
2016-01-25 09:07:41 -08:00
Edward Hennis
b4f8dc7abf Set version to 0.31.0-b3 2016-01-20 22:46:38 -05:00
Miguel Portilla
14dde47173 Convert STAmount switchovers to tls (RIPD-1068) 2016-01-20 22:46:09 -05:00
Miguel Portilla
4fb6bf3e67 Add coroutine thread specific storage 2016-01-20 22:46:07 -05:00
Miguel Portilla
f73c55a922 Add JobCoro::join 2016-01-20 22:46:06 -05:00
Vinnie Falco
49c86768e6 Peer to peer network simulator:
* Refine the Peer concept
* Remove incremental consensus simulations (coverage)
* Add unit test (coverage)
* Fix BasicNetwork::remove
2016-01-20 22:46:04 -05:00
Scott Schurr
0fca91c6c1 Remove tapENABLE_TESTING. 2016-01-20 22:46:02 -05:00
wilsonianb
749b4adc7c Add manifests subscriptions
Add verify method to manifest script to check signature
2016-01-20 22:46:00 -05:00
Edward Hennis
a67e4ab9f1 Port test/transaction_ordering_test.js to C++ 2016-01-20 22:45:58 -05:00
Edward Hennis
e0b2a26805 TxQ unit tests account for localTx. 2016-01-20 22:45:56 -05:00
Edward Hennis
6c5b23b317 OpenLedger::accept, flip order of modifier and locals:
* And call in to the TxQ if enabled.
2016-01-20 22:45:55 -05:00
Edward Hennis
8da2a724fb Close/advance Env ledgers through RPC interface 2016-01-20 22:45:54 -05:00
Vinnie Falco
d5363d1a85 Submit Env transactions through RPC interface 2016-01-20 22:45:53 -05:00
seelabs
8f74ee1d96 Add sanitize build support 2016-01-20 22:45:52 -05:00
Miguel Portilla
796ee8e3de Path find source currency limits (RIPD-1062) 2016-01-20 22:45:50 -05:00
Nik Bougalis
25f611d0ec Delete unfunded offers in predictable order 2016-01-20 22:45:49 -05:00
Nik Bougalis
08e518af73 Correctly interrogate child process status 2016-01-20 22:36:57 -05:00
Nik Bougalis
5f4fe9fccb Set version to 0.30.1-rc3 2016-01-20 15:56:16 -08:00
Nik Bougalis
db9885e1fc Delete unfunded offers in predictable order 2016-01-20 15:56:10 -08:00
Nik Bougalis
27673c1c3f Set version to 0.31.0-b2 2016-01-19 15:43:13 -08:00
Miguel Portilla
3394129894 Remove unused declaration 2016-01-19 15:43:03 -08:00
Nik Bougalis
57625e06ed Increase minimum local fee 2016-01-14 14:11:20 -08:00
Nik Bougalis
bdfb5fa2bc Set version to 0.30.1-rc2 2016-01-14 13:36:34 -08:00
Nik Bougalis
b2c9179100 Increase minimum local fee 2016-01-14 13:36:18 -08:00
Nik Bougalis
d7935192dd Set version to 0.31.0-b1 2016-01-12 18:50:58 -08:00
Howard Hinnant
97d5325468 Correct handling of comparators in boost::intrusive:
This facilitates the port of rippled to boost 1.60 while
maintaining compatibility with previous versions of boost.
2016-01-12 18:50:53 -08:00
Scott Schurr
8433851652 Add SignerList support to account_objects (RIPD-1061):
Return just SignerList objects on an account using the
account_objects RPC command with "type":"signer_list".
2016-01-12 18:45:36 -08:00
Edward Hennis
f7b2b84ece Integration test for transaction ordering. 2016-01-12 18:45:36 -08:00
Edward Hennis
8be67c1766 Speed up out of order transaction processing (RIPD-239):
* After successfully applying a transaction to the open ledger, resubmit any held transactions from the same account.
* All held transactions will continue to be retried after consensus round.
2016-01-12 18:45:36 -08:00
Edward Hennis
4d2e7ed404 LedgerMaster hash lookups return boost::optional. 2016-01-12 18:45:36 -08:00
Edward Hennis
e1018546ac Devirtualize LedgerMaster. 2016-01-12 18:45:36 -08:00
JoelKatz
44fcab1081 SHAMap improvements:
* Run key SHAMap unit tests on both backed and unbacked maps
* Remove obsolete version of SHAMapTree::addRootNode
* Our position maps should be unbacked and immutable
* Minimize hash operations for unbacked SHAMaps
  Not setting the sequence numbers to zero in
  SHAMap::walkSubTree causes extra hashes to be
  performed on subsequent operations
2016-01-12 18:45:36 -08:00
JoelKatz
6dab1657b1 Some pathfinding cleanups and optimizations:
* Reduce the log level of an expensive debug message
* Don't hold the request lock while pathfinding
2016-01-12 18:45:36 -08:00
Nik Bougalis
60ad21ae0d Pathfinding cleanups:
* Return std::pair instead of returning by reference
* Use std algorithms when possible
* Use auto and C++14 lambdas
2016-01-12 18:45:36 -08:00
Nik Bougalis
3974ddd8f7 Remove RippleAddress:
The RippleAddress class was used to represent a number of fundamentally
different types: account public keys, account secret keys, node public
keys, node secret keys, seeds and generators.

The class is replaced by the following types:
* PublicKey for account and node public keys
* SecretKey for account and node private keys
* Generator for generating secp256k1 accounts
* Seed for account, node and generator seeds
2016-01-12 18:45:36 -08:00
Nik Bougalis
e0af6ec567 Streamlined UNL/validator list:
The new code removes the ability to specify domain names
in the [validators] configuration block, and no longer
supports the [validators_site] option.

More details on the supported configurations are available
under doc/rippled-example.cfg.
2016-01-12 18:45:35 -08:00
Nik Bougalis
0a96f3a249 Simplify Beast:
* Remove obsolete RNG facilities
* Flatten directory structure
* Use std::recursive_mutex instead of beast::RecursiveMutex
2016-01-12 18:45:35 -08:00
Nik Bougalis
40363f96a9 Generic PRNG framework:
* A new, unified interface for generating random numbers and
  filling buffers supporting any engine that fits the
  UniformRandomNumberGenerator concept;
* Automatically seeded replacement for rand using the fast
  xorshift+ PRNG engine;
* A CSPRNG engine that can be used with the new framework
  when needing to to generate cryptographically secure
  randomness.
* Unit test cleanups to work with new engine.
2016-01-12 18:45:35 -08:00
Nik Bougalis
1c9577a1ac Simplify blob encoding 2016-01-12 16:06:18 -08:00
Nik Bougalis
a7a30396be Define NOMINMAX for Windows 2016-01-12 16:06:18 -08:00
Nik Bougalis
fee19390f5 Improve watchdog restart logic:
Stop attempting to restart the server after five consecutive
restarts fail to remain operational for at least ten seconds.
2016-01-12 16:06:18 -08:00
815 changed files with 58895 additions and 90850 deletions

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env bash
#
# This scripts installs boost and protobuf built with clang. This is needed on
# ubuntu 15.10 when building with clang
# It will build these in a 'clang' subdirectory that it creates below the directory
# this script is run from. If a clang directory already exists the script will refuse
# to run.
if hash lsb_release 2>/dev/null; then
if [ $(lsb_release -si) == "Ubuntu" ]; then
ubuntu_release=$(lsb_release -sr)
fi
fi
if [ -z "${ubuntu_release}" ]; then
echo "System not supported"
exit 1
fi
if ! hash clang 2>/dev/null; then
clang_version=3.7
sudo apt-get -y install clang-${clang_version}
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${clang_version} 99 clang++
hash -r
if ! hash clang 2>/dev/null; then
echo "Please install clang"
exit 1
fi
fi
if [ ${ubuntu_release} != "15.10" ]; then
echo "clang specific boost and protobuf not needed"
exit 0
fi
if [ -d clang ]; then
echo "clang directory already exists. Cowardly refusing to run"
exit 1
fi
if ! hash wget 2>/dev/null; then
sudo apt-get -y install wget
hash -r
if ! hash wget 2>/dev/null; then
echo "Please install wget"
exit 1
fi
fi
num_procs=$(lscpu -p | grep -v '^#' | sort -u -t, -k 2,4 | wc -l) # pysical cores
mkdir clang
pushd clang > /dev/null
# Install protobuf
pb=protobuf-2.6.1
pb_tar=${pb}.tar.gz
wget -O ${pb_tar} https://github.com/google/protobuf/releases/download/v2.6.1/${pb_tar}
tar xf ${pb_tar}
rm ${pb_tar}
pushd ${pb} > /dev/null
./configure CC=clang CXX=clang++ CXXFLAGS='-std=c++14 -O3 -g'
make -j${num_procs}
popd > /dev/null
# Install boost
boost_ver=1.60.0
bd=boost_${boost_ver//./_}
bd_tar=${bd}.tar.gz
wget -O ${bd_tar} http://sourceforge.net/projects/boost/files/boost/${boost_ver}/${bd_tar}
tar xf ${bd_tar}
rm ${bd_tar}
pushd ${bd} > /dev/null
./bootstrap.sh
./b2 toolset=clang -j${num_procs}
popd > /dev/null
popd > /dev/null

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -61,10 +61,16 @@ The following environment variables modify the build environment:
Path to the boost directory. Path to the boost directory.
OPENSSL_ROOT OPENSSL_ROOT
Path to the openssl directory. Path to the openssl directory.
PROTOBUF_DIR PROTOBUF_ROOT
Path to the protobuf directory. This is usually only needed when Path to the protobuf directory.
the installed protobuf library uses a different ABI than clang CLANG_PROTOBUF_ROOT
(as with ubuntu 15.10). Override the path to the protobuf directory for the clang toolset. This is
usually only needed when the installed protobuf library uses a different
ABI than clang (as with ubuntu 15.10).
CLANG_BOOST_ROOT
Override the path to the boost directory for the clang toolset. This is
usually only needed when the installed protobuf library uses a different
ABI than clang (as with ubuntu 15.10).
The following extra options may be used: The following extra options may be used:
--ninja Generate a `build.ninja` build file for the specified target --ninja Generate a `build.ninja` build file for the specified target
@@ -73,6 +79,8 @@ The following extra options may be used:
--static On linux, link protobuf, openssl, libc++, and boost statically --static On linux, link protobuf, openssl, libc++, and boost statically
--sanitize=[address, thread] On gcc & clang, add sanitizer instrumentation
GCC 5: If the gcc toolchain is used, gcc version 5 or better is required. On GCC 5: If the gcc toolchain is used, gcc version 5 or better is required. On
linux distros that ship with gcc 4 (ubuntu < 15.10), rippled will force gcc linux distros that ship with gcc 4 (ubuntu < 15.10), rippled will force gcc
to use gcc4's ABI (there was an ABI change between versions). This allows us to use gcc4's ABI (there was an ABI change between versions). This allows us
@@ -122,6 +130,9 @@ import scons_to_ninja
AddOption('--ninja', dest='ninja', action='store_true', AddOption('--ninja', dest='ninja', action='store_true',
help='generate ninja build file build.ninja') help='generate ninja build file build.ninja')
AddOption('--sanitize', dest='sanitize', choices=['address', 'thread'],
help='Build with sanitizer support (gcc and clang only).')
AddOption('--static', dest='static', action='store_true', AddOption('--static', dest='static', action='store_true',
help='On linux, link protobuf, openssl, libc++, and boost statically') help='On linux, link protobuf, openssl, libc++, and boost statically')
@@ -348,24 +359,9 @@ def config_base(env):
,{'HAVE_USLEEP' : '1'} ,{'HAVE_USLEEP' : '1'}
,{'SOCI_CXX_C11' : '1'} ,{'SOCI_CXX_C11' : '1'}
,'_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS' ,'_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS'
,'-DBOOST_NO_AUTO_PTR' ,'BOOST_NO_AUTO_PTR'
]) ])
try:
BOOST_ROOT = os.path.normpath(os.environ['BOOST_ROOT'])
env.Append(LIBPATH=[
os.path.join(BOOST_ROOT, 'stage', 'lib'),
])
env['BOOST_ROOT'] = BOOST_ROOT
except KeyError:
pass
try:
protobuf_dir = os.environ['PROTOBUF_DIR']
env.Append(LIBPATH=[protobuf_dir])
except KeyError:
pass
if Beast.system.windows: if Beast.system.windows:
try: try:
OPENSSL_ROOT = os.path.normpath(os.environ['OPENSSL_ROOT']) OPENSSL_ROOT = os.path.normpath(os.environ['OPENSSL_ROOT'])
@@ -400,7 +396,7 @@ def add_static_libs(env, static_libs, dyn_libs=None):
for k,l in [('STATICLIBS', static_libs or []), ('DYNAMICLIBS', dyn_libs or [])]: for k,l in [('STATICLIBS', static_libs or []), ('DYNAMICLIBS', dyn_libs or [])]:
c = env.get(k, '') c = env.get(k, '')
for f in l: for f in l:
c += ' -l' + f c += ' -l' + f
env[k] = c env[k] = c
def get_libs(lib, static): def get_libs(lib, static):
@@ -425,33 +421,77 @@ def get_libs(lib, static):
else: else:
static_libs.append(l) static_libs.append(l)
return (static_libs, dynamic_libs) return (static_libs, dynamic_libs)
except: except Exception as e:
raise Exception('pkg-config failed for ' + lib) raise Exception('pkg-config failed for ' + lib + '; Exception: ' + str(e))
# Set toolchain and variant specific construction variables def add_sanitizer (toolchain, env):
def config_env(toolchain, variant, env): san = GetOption('sanitize')
if is_debug_variant(variant): if not san: return
env.Append(CPPDEFINES=['DEBUG', '_DEBUG']) san_to_lib = {'address': 'asan', 'thread': 'tsan'}
if toolchain not in Split('clang gcc'):
raise Exception("Sanitizers are only supported for gcc and clang")
env.Append(CCFLAGS=['-fsanitize='+san, '-fno-omit-frame-pointer'])
env.Append(LINKFLAGS=['-fsanitize='+san])
add_static_libs(env, [san_to_lib[san]])
env.Append(CPPDEFINES=['SANITIZER='+san_to_lib[san].upper()])
elif variant == 'release' or variant == 'profile': def add_boost_and_protobuf(toolchain, env):
env.Append(CPPDEFINES=['NDEBUG']) def get_environ_value(candidates):
for c in candidates:
try:
return os.environ[c]
except KeyError:
pass
raise KeyError('Environment variable not set')
if 'BOOST_ROOT' in env: try:
br_cands = ['CLANG_BOOST_ROOT'] if toolchain == 'clang' else []
br_cands.append('BOOST_ROOT')
BOOST_ROOT = os.path.normpath(get_environ_value(br_cands))
env.Append(LIBPATH=[
os.path.join(BOOST_ROOT, 'stage', 'lib'),
])
env['BOOST_ROOT'] = BOOST_ROOT
if toolchain == 'gcc': if toolchain == 'gcc':
env.Append(CCFLAGS=['-isystem' + env['BOOST_ROOT']]) env.Append(CCFLAGS=['-isystem' + env['BOOST_ROOT']])
else: else:
env.Append(CPPPATH=[ env.Append(CPPPATH=[
env['BOOST_ROOT'], env['BOOST_ROOT'],
]) ])
except KeyError:
pass
try:
pb_cands = ['CLANG_PROTOBUF_ROOT'] if toolchain == 'clang' else []
pb_cands.append('PROTOBUF_ROOT')
PROTOBUF_ROOT = os.path.normpath(get_environ_value(pb_cands))
env.Append(LIBPATH=[PROTOBUF_ROOT + '/src/.libs'])
if not should_link_static() and toolchain in['clang', 'gcc']:
env.Append(LINKFLAGS=['-Wl,-rpath,' + PROTOBUF_ROOT + '/src/.libs'])
env['PROTOBUF_ROOT'] = PROTOBUF_ROOT
env.Append(CPPPATH=[env['PROTOBUF_ROOT'] + '/src',])
except KeyError:
pass
# Set toolchain and variant specific construction variables
def config_env(toolchain, variant, env):
add_boost_and_protobuf(toolchain, env)
if is_debug_variant(variant):
env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
elif variant == 'release' or variant == 'profile':
env.Append(CPPDEFINES=['NDEBUG'])
if should_link_static() and not Beast.system.linux: if should_link_static() and not Beast.system.linux:
raise Exception("Static linking is only implemented for linux.") raise Exception("Static linking is only implemented for linux.")
add_sanitizer(toolchain, env)
if toolchain in Split('clang gcc'): if toolchain in Split('clang gcc'):
if Beast.system.linux: if Beast.system.linux:
link_static = should_link_static() link_static = should_link_static()
for l in ['openssl', 'protobuf']: for l in ['openssl', 'protobuf']:
static, dynamic = get_libs(l, link_static) static, dynamic = get_libs(l, link_static)
if link_static: if link_static:
add_static_libs(env, static, dynamic) add_static_libs(env, static, dynamic)
else: else:
@@ -643,6 +683,7 @@ def config_env(toolchain, variant, env):
'_SCL_SECURE_NO_WARNINGS', '_SCL_SECURE_NO_WARNINGS',
'_CRT_SECURE_NO_WARNINGS', '_CRT_SECURE_NO_WARNINGS',
'WIN32_CONSOLE', 'WIN32_CONSOLE',
'NOMINMAX'
]) ])
if variant == 'debug': if variant == 'debug':
env.Append(LIBS=[ env.Append(LIBS=[
@@ -864,8 +905,8 @@ def get_classic_sources(toolchain):
append_sources(result, *list_sources('src/ripple/protocol', '.cpp')) append_sources(result, *list_sources('src/ripple/protocol', '.cpp'))
append_sources(result, *list_sources('src/ripple/rpc', '.cpp')) append_sources(result, *list_sources('src/ripple/rpc', '.cpp'))
append_sources(result, *list_sources('src/ripple/shamap', '.cpp')) append_sources(result, *list_sources('src/ripple/shamap', '.cpp'))
append_sources(result, *list_sources('src/ripple/server', '.cpp'))
append_sources(result, *list_sources('src/ripple/test', '.cpp')) append_sources(result, *list_sources('src/ripple/test', '.cpp'))
append_sources(result, *list_sources('src/ripple/unl', '.cpp'))
if use_shp(toolchain): if use_shp(toolchain):
cc_flags = {'CCFLAGS': ['--system-header-prefix=rocksdb2']} cc_flags = {'CCFLAGS': ['--system-header-prefix=rocksdb2']}
@@ -908,8 +949,8 @@ def get_unity_sources(toolchain):
'src/ripple/unity/protocol.cpp', 'src/ripple/unity/protocol.cpp',
'src/ripple/unity/rpcx.cpp', 'src/ripple/unity/rpcx.cpp',
'src/ripple/unity/shamap.cpp', 'src/ripple/unity/shamap.cpp',
'src/ripple/unity/server.cpp',
'src/ripple/unity/test.cpp', 'src/ripple/unity/test.cpp',
'src/ripple/unity/unl.cpp',
) )
if use_shp(toolchain): if use_shp(toolchain):
@@ -1054,7 +1095,6 @@ for tu_style in ['classic', 'unity']:
'src/ripple/unity/protobuf.cpp', 'src/ripple/unity/protobuf.cpp',
'src/ripple/unity/ripple.proto.cpp', 'src/ripple/unity/ripple.proto.cpp',
'src/ripple/unity/resource.cpp', 'src/ripple/unity/resource.cpp',
'src/ripple/unity/server.cpp',
'src/ripple/unity/websocket02.cpp', 'src/ripple/unity/websocket02.cpp',
**cc_flags **cc_flags
) )
@@ -1097,11 +1137,6 @@ for tu_style in ['classic', 'unity']:
] ]
) )
object_builder.add_source_files(
'src/ripple/unity/websocket04.cpp',
CPPPATH='src/websocketpp',
)
if toolchain == "clang" and Beast.system.osx: if toolchain == "clang" and Beast.system.osx:
object_builder.add_source_files('src/ripple/unity/beastobjc.mm') object_builder.add_source_files('src/ripple/unity/beastobjc.mm')

View File

@@ -83,5 +83,5 @@ test_script:
- build\\rippled --unittest - build\\rippled --unittest
# Run the integration tests # Run the integration tests
- npm install - npm install --progress=false
- npm test - npm test

View File

@@ -37,5 +37,5 @@ else
fi fi
# Run NPM tests # Run NPM tests
npm install npm install --progress=false
npm test --rippled=$RIPPLED_PATH npm test --rippled=$RIPPLED_PATH

View File

@@ -22,6 +22,9 @@ Usage:
sign <sequence> <validator-public> <master-secret> sign <sequence> <validator-public> <master-secret>
Create a new signed manifest with the given sequence Create a new signed manifest with the given sequence
number, validator public key, and master secret key. number, validator public key, and master secret key.
verify <sequence> <validator-public> <signature> <master-public>
Verify hex-encoded manifest signature with master public key.
""" """
def prepend_length_byte(b): def prepend_length_byte(b):
@@ -113,6 +116,16 @@ def get_signature(seq, validator_public_key_human, private_key_human):
m1 = sign_manifest(m, private_key, pk) m1 = sign_manifest(m, private_key, pk)
return base64.b64encode(m1) return base64.b64encode(m1)
def verify_signature(seq, validator_public_key_human, public_key_human, signature):
v, validator_public_key = Base58.decode_version(validator_public_key_human)
check_validator_public(v, validator_public_key)
v, public_key = Base58.decode_version(public_key_human)
m = make_manifest(public_key, validator_public_key, seq)
public_key = public_key[1:] # Remove ED25519_BYTE
sig = signature.decode('hex')
ed25519.checkvalid(sig, 'MAN\0' + m, public_key)
# Testable versions of functions. # Testable versions of functions.
def perform_create(urandom=os.urandom, print=print): def perform_create(urandom=os.urandom, print=print):
@@ -131,6 +144,12 @@ def perform_sign(
print(wrap(get_signature( print(wrap(get_signature(
int(seq), validator_public_key_human, private_key_human))) int(seq), validator_public_key_human, private_key_human)))
def perform_verify(
seq, validator_public_key_human, public_key_human, signature, print=print):
verify_signature(
int(seq), validator_public_key_human, public_key_human, signature)
print('Signature valid for', public_key_human)
# Externally visible versions of functions. # Externally visible versions of functions.
def create(): def create():
perform_create() perform_create()
@@ -141,6 +160,8 @@ def check(s):
def sign(seq, validator_public_key_human, private_key_human): def sign(seq, validator_public_key_human, private_key_human):
perform_sign(seq, validator_public_key_human, private_key_human) perform_sign(seq, validator_public_key_human, private_key_human)
def verify(seq, validator_public_key_human, public_key_human, signature):
perform_verify(seq, validator_public_key_human, public_key_human, signature)
def usage(*errors): def usage(*errors):
if errors: if errors:
@@ -148,7 +169,7 @@ def usage(*errors):
print(USAGE) print(USAGE)
return not errors return not errors
_COMMANDS = dict((f.__name__, f) for f in (create, check, sign)) _COMMANDS = dict((f.__name__, f) for f in (create, check, sign, verify))
def run_command(args): def run_command(args):
if not args: if not args:

View File

@@ -14,6 +14,10 @@ class test_Sign(TestCase):
'JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2' 'JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2'
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJM' 'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJM'
'zqkBJwDz30b2SkxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA') 'zqkBJwDz30b2SkxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA')
VALIDATOR_KEY_HUMAN = 'n9JijuoCv8ubEy5ag3LiX3hyq27GaLJsitZPbQ6APkwx2MkUXq8E'
SIGNATURE_HEX = (
'0a1546caa29c887f9fcb5e6143ea101b31fb5895a5cdfa24939301c66ff51794'
'a0b729e0ebbf576f2cc7cdb9f68c2366324a53b8e1ecf16f3c17bebbdb8d7102')
def setUp(self): def setUp(self):
self.results = [] self.results = []
@@ -96,6 +100,11 @@ class test_Sign(TestCase):
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJM' 'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJM'
'zqkBJwDz30b2SkxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA') 'zqkBJwDz30b2SkxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA')
def test_verify_signature(self):
Sign.verify_signature(self.SEQUENCE, self.VALIDATOR_KEY_HUMAN,
'nHUUaKHpxyRP4TZZ79tTpXuTpoM8pRNs5crZpGVA5jdrjib5easY',
self.SIGNATURE_HEX)
def test_check(self): def test_check(self):
public = Base58.encode_version(Base58.VER_NODE_PRIVATE, 32 * 'k') public = Base58.encode_version(Base58.VER_NODE_PRIVATE, 32 * 'k')
Sign.perform_check(public, self.print) Sign.perform_check(public, self.print)
@@ -125,3 +134,8 @@ class test_Sign(TestCase):
'Z2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJMzqkBJwDz30b2S\n' 'Z2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJMzqkBJwDz30b2S\n'
'kxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA'], 'kxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA'],
{}]]) {}]])
def test_verify(self):
Sign.perform_verify(self.SEQUENCE, self.VALIDATOR_KEY_HUMAN,
'nHUUaKHpxyRP4TZZ79tTpXuTpoM8pRNs5crZpGVA5jdrjib5easY',
self.SIGNATURE_HEX, print=self.print)

View File

@@ -30,7 +30,7 @@ test:
# gdb segfaults # gdb segfaults
# - cat script.gdb | gdb --ex 'set print thread-events off' --return-child-result --args build/clang.debug/rippled --unittest # - cat script.gdb | gdb --ex 'set print thread-events off' --return-child-result --args build/clang.debug/rippled --unittest
- build/clang.debug/rippled --unittest - build/clang.debug/rippled --unittest
- npm install - npm install --progress=false
# Use build/(gcc|clang).debug/rippled # Use build/(gcc|clang).debug/rippled
- | - |
echo "exports.default_server_config = {\"rippled_path\" : \"$HOME/rippled/build/clang.debug/rippled\"};" > test/config.js echo "exports.default_server_config = {\"rippled_path\" : \"$HOME/rippled/build/clang.debug/rippled\"};" > test/config.js

View File

@@ -503,17 +503,11 @@
# #
# [validators] # [validators]
# #
# List of nodes to always accept as validators. Nodes are specified by domain # List of the validation public keys of nodes to always accept as validators.
# or public key. # A comment may, optionally, be associated with each entry, separated by
# # whitespace from the validation public key.
# For domains, rippled will probe for https web servers at the specified
# domain in the following order: ripple.DOMAIN, www.DOMAIN, DOMAIN
#
# For public key entries, a comment may optionally be specified after adding
# a space to the public key.
# #
# Examples: # Examples:
# ripple.com
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5 # n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe # n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
# #
@@ -521,33 +515,27 @@
# #
# [validators_file] # [validators_file]
# #
# Path to file contain a list of nodes to always accept as validators. Use # Path to a file that contains the validation public keys of nodes to always
# this to specify a file other than this file to manage your validators list. # accept as validators. A comment may, optionally, be associated with each
# entry, separated by whitespace from the validation public key.
# #
# If this entry is not present or empty and no nodes from previous runs were # The contents of the file should include a [validators] entry, followed by
# found in the database, rippled will look for a validators.txt in the config # a list of validation public keys of nodes to always accept as validators,
# directory. If not found there, it will attempt to retrieve the file from # one per line, optionally followed by a comment separated by whitespace:
# the [validators_site] web site.
#
# After specifying a different [validators_file] or changing the contents of
# the validators file, issue a RPC unl_load command to have rippled load the
# file.
# #
# Specify the file by specifying its full path. # Specify the file by specifying its full path.
# #
# Examples: # Examples:
# C:/home/johndoe/ripple/validators.txt # /home/ripple/validators.txt
# /home/johndoe/ripple/validators.txt # C:/home/ripple/validators.txt
#
#
#
# [validators_site]
#
# Specifies where to find validators.txt for UNL boostrapping and RPC
# unl_network command.
#
# Example: ripple.com
# #
# Example content:
# [validators]
# n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1
# n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2
# n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
# n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
# #
# #
# [path_search] # [path_search]

View File

@@ -149,13 +149,6 @@
#define RIPPLE_USE_VALIDATORS 0 #define RIPPLE_USE_VALIDATORS 0
#endif #endif
/** Config: RIPPLE_PROPOSE_FEATURES
This determines whether to add any features to the proposed transaction set.
*/
#ifndef RIPPLE_PROPOSE_AMENDMENTS
#define RIPPLE_PROPOSE_AMENDMENTS 0
#endif
/** Config: RIPPLE_SINGLE_IO_SERVICE_THREAD /** Config: RIPPLE_SINGLE_IO_SERVICE_THREAD
When set, restricts the number of threads calling io_service::run to one. When set, restricts the number of threads calling io_service::run to one.
This is useful when debugging. This is useful when debugging.

View File

@@ -1,106 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ARITHMETIC_H_INCLUDED
#define BEAST_ARITHMETIC_H_INCLUDED
#include <beast/Config.h>
#include <cmath>
#include <cstdint>
#include <algorithm>
namespace beast {
//==============================================================================
/** Constrains a value to keep it within a given range.
This will check that the specified value lies between the lower and upper bounds
specified, and if not, will return the nearest value that would be in-range. Effectively,
it's like calling bmax (lowerLimit, bmin (upperLimit, value)).
Note that it expects that lowerLimit <= upperLimit. If this isn't true,
the results will be unpredictable.
@param lowerLimit the minimum value to return
@param upperLimit the maximum value to return
@param valueToConstrain the value to try to return
@returns the closest value to valueToConstrain which lies between lowerLimit
and upperLimit (inclusive)
@see blimit0To, bmin, bmax
*/
template <typename Type>
inline Type blimit (const Type lowerLimit,
const Type upperLimit,
const Type valueToConstrain) noexcept
{
// if these are in the wrong order, results are unpredictable.
bassert (lowerLimit <= upperLimit);
return (valueToConstrain < lowerLimit) ? lowerLimit
: ((upperLimit < valueToConstrain) ? upperLimit
: valueToConstrain);
}
/** Returns true if a value is at least zero, and also below a specified upper limit.
This is basically a quicker way to write:
@code valueToTest >= 0 && valueToTest < upperLimit
@endcode
*/
template <typename Type>
inline bool isPositiveAndBelow (Type valueToTest, Type upperLimit) noexcept
{
bassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
return Type() <= valueToTest && valueToTest < upperLimit;
}
template <>
inline bool isPositiveAndBelow (const int valueToTest, const int upperLimit) noexcept
{
bassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
return static_cast <unsigned int> (valueToTest) < static_cast <unsigned int> (upperLimit);
}
//==============================================================================
/** Handy function for getting the number of elements in a simple const C array.
E.g.
@code
static int myArray[] = { 1, 2, 3 };
int numElements = numElementsInArray (myArray) // returns 3
@endcode
*/
template <typename Type, int N>
int numElementsInArray (Type (&array)[N])
{
(void) array; // (required to avoid a spurious warning in MS compilers)
(void) sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator
return N;
}
}
#endif

View File

@@ -22,7 +22,6 @@
#include <beast/chrono/abstract_clock.h> #include <beast/chrono/abstract_clock.h>
#include <beast/chrono/basic_seconds_clock.h> #include <beast/chrono/basic_seconds_clock.h>
#include <beast/chrono/chrono_io.h>
#include <beast/chrono/chrono_util.h> #include <beast/chrono/chrono_util.h>
#include <beast/chrono/manual_clock.h> #include <beast/chrono/manual_clock.h>
#include <beast/chrono/ratio_io.h> #include <beast/chrono/ratio_io.h>

View File

@@ -40,37 +40,6 @@ template <typename Type>
void zerostruct (Type& structure) noexcept void zerostruct (Type& structure) noexcept
{ memset (&structure, 0, sizeof (structure)); } { memset (&structure, 0, sizeof (structure)); }
/** Delete an object pointer, and sets the pointer to null.
Remember that it's not good c++ practice to use delete directly - always try to use a std::unique_ptr
or other automatic lifetime-management system rather than resorting to deleting raw pointers!
*/
template <typename Type>
void deleteAndZero (Type& pointer)
{ delete pointer; pointer = nullptr; }
/** A handy function which adds a number of bytes to any type of pointer and returns the result.
This can be useful to avoid casting pointers to a char* and back when you want to move them by
a specific number of bytes,
*/
template <typename Type, typename IntegerType>
Type* addBytesToPointer (Type* pointer, IntegerType bytes) noexcept
{ return (Type*) (((char*) pointer) + bytes); }
/** A handy function which returns the difference between any two pointers, in bytes.
The address of the second pointer is subtracted from the first, and the difference in bytes is returned.
*/
template <typename Type1, typename Type2>
int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept
{ return (int) (((const char*) pointer1) - (const char*) pointer2); }
/** If a pointer is non-null, this returns a new copy of the object that it points to, or safely returns
nullptr if the pointer is null.
*/
template <class Type>
Type* createCopyIfNotNull (const Type* pointer)
{ return pointer != nullptr ? new Type (*pointer) : nullptr; }
//============================================================================== //==============================================================================
#if BEAST_MAC || BEAST_IOS || DOXYGEN #if BEAST_MAC || BEAST_IOS || DOXYGEN

View File

@@ -1,27 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_STRINGS_H_INCLUDED
#define BEAST_STRINGS_H_INCLUDED
#include <beast/strings/String.h>
#include <beast/strings/NewLine.h>
#endif

View File

@@ -20,15 +20,9 @@
#ifndef BEAST_THREADS_H_INCLUDED #ifndef BEAST_THREADS_H_INCLUDED
#define BEAST_THREADS_H_INCLUDED #define BEAST_THREADS_H_INCLUDED
#include <beast/threads/UnlockGuard.h>
#include <beast/threads/TryLockGuard.h>
#include <beast/threads/SharedLockGuard.h>
#include <beast/threads/SharedMutexAdapter.h>
#include <beast/threads/SpinLock.h>
#include <beast/threads/Stoppable.h> #include <beast/threads/Stoppable.h>
#include <beast/threads/Thread.h> #include <beast/threads/Thread.h>
#include <beast/threads/WaitableEvent.h> #include <beast/threads/WaitableEvent.h>
#include <beast/threads/ScopedWrapperContext.h>
#include <beast/threads/semaphore.h> #include <beast/threads/semaphore.h>

View File

@@ -23,7 +23,6 @@
#include <beast/Config.h> #include <beast/Config.h>
#include <beast/chrono/impl/chrono_io.cpp>
#include <beast/chrono/impl/RelativeTime.cpp> #include <beast/chrono/impl/RelativeTime.cpp>
#include <beast/chrono/tests/abstract_clock.test.cpp> #include <beast/chrono/tests/abstract_clock.test.cpp>

View File

@@ -25,7 +25,6 @@
#define BEAST_CHRONO_RELATIVETIME_H_INCLUDED #define BEAST_CHRONO_RELATIVETIME_H_INCLUDED
#include <beast/Config.h> #include <beast/Config.h>
#include <beast/strings/String.h>
#include <string> #include <string>
#include <sstream> #include <sstream>
@@ -145,24 +144,6 @@ public:
*/ */
value_type inWeeks() const noexcept; value_type inWeeks() const noexcept;
/** Returns a readable textual description of the time.
The exact format of the string returned will depend on
the magnitude of the time - e.g.
"1 min 4 secs", "1 hr 45 mins", "2 weeks 5 days", "140 ms"
so that only the two most significant units are printed.
The returnValueForZeroTime value is the result that is returned if the
length is zero. Depending on your application you might want to use this
to return something more relevant like "empty" or "0 secs", etc.
@see inMilliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks
*/
String getDescription (const String& returnValueForZeroTime = "0") const;
std::string to_string () const;
template <typename Number> template <typename Number>
RelativeTime operator+ (Number seconds) const noexcept RelativeTime operator+ (Number seconds) const noexcept
{ return RelativeTime (numSeconds + seconds); } { return RelativeTime (numSeconds + seconds); }
@@ -204,12 +185,6 @@ RelativeTime operator+ (RelativeTime t1, RelativeTime t2) noexcept;
/** Subtracts two RelativeTimes. */ /** Subtracts two RelativeTimes. */
RelativeTime operator- (RelativeTime t1, RelativeTime t2) noexcept; RelativeTime operator- (RelativeTime t1, RelativeTime t2) noexcept;
inline std::ostream& operator<< (std::ostream& os, RelativeTime const& diff)
{
os << diff.to_string();
return os;
}
} }
#endif #endif

View File

@@ -107,6 +107,7 @@ public:
for (auto iter : workers_) for (auto iter : workers_)
iter->sample(); iter->sample();
using namespace std::chrono;
clock_type::time_point const when ( clock_type::time_point const when (
floor <seconds> ( floor <seconds> (
clock_type::now().time_since_epoch()) + clock_type::now().time_since_epoch()) +

View File

@@ -1,803 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// chrono_io
//
// (C) Copyright Howard Hinnant
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt).
#ifndef BEAST_CHRONO_CHRONO_IO_H_INCLUDED
#define BEAST_CHRONO_CHRONO_IO_H_INCLUDED
#include <beast/Config.h>
#include <ctime>
#include <locale>
/*
chrono_io synopsis
#include <chrono>
#include <ratio_io>
namespace std
{
namespace chrono
{
enum duration_style {prefix, symbol};
enum timezone {utc, local};
// facets
class durationpunct
: public locale::facet
{
public:
static locale::id id;
explicit durationpunct(size_t refs = 0);
explicit durationpunct(duration_style fmt, size_t refs = 0);
bool is_symbol_name() const noexcept;
bool is_prefix_name() const noexcept;
};
template <class charT>
class timepunct
: public locale::facet
{
public:
typedef basic_string<charT> string_type;
static locale::id id;
explicit timepunct(size_t refs = 0);
timepunct(timezone tz, string_type fmt, size_t refs = 0);
const string_type& fmt() const noexcept;
std::chrono::timezone timezone() const noexcept;
};
// manipulators
class duration_fmt
{
public:
explicit duration_fmt(duration_style f) noexcept;
explicit operator duration_style() const noexcept;
};
unspecified time_fmt(timezone tz);
template<class charT>
unspecified time_fmt(timezone tz, basic_string<charT> fmt);
template<class charT>
unspecified time_fmt(timezone tz, const charT* fmt);
template<class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, duration_fmt d);
template<class charT, class traits>
std::basic_istream<charT, traits>&
operator>>(std::basic_istream<charT, traits>& is, duration_fmt d);
// duration I/O
template <class charT, class Traits, class Rep, class Period>
basic_ostream<charT, Traits>&
operator<<(basic_ostream<charT, Traits>& os, const duration<Rep, Period>& d);
template <class charT, class Traits, class Rep, class Period>
basic_istream<charT, Traits>&
operator>>(basic_istream<charT, Traits>& is, duration<Rep, Period>& d);
// system_clock I/O
template <class charT, class Traits, class Duration>
basic_ostream<charT, Traits>&
operator<<(basic_ostream<charT, Traits>& os,
const time_point<system_clock, Duration>& tp);
template <class charT, class Traits, class Duration>
basic_istream<charT, Traits>&
operator>>(basic_istream<charT, Traits>& is,
time_point<system_clock, Duration>& tp);
// steady_clock I/O
template <class charT, class Traits, class Duration>
basic_ostream<charT, Traits>&
operator<<(basic_ostream<charT, Traits>& os,
const time_point<steady_clock, Duration>& tp);
template <class charT, class Traits, class Duration>
basic_istream<charT, Traits>&
operator>>(basic_istream<charT, Traits>& is,
time_point<steady_clock, Duration>& tp);
// high_resolution_clock I/O
template <class charT, class Traits, class Duration>
basic_ostream<charT, Traits>&
operator<<(basic_ostream<charT, Traits>& os,
const time_point<high_resolution_clock, Duration>& tp);
template <class charT, class Traits, class Duration>
basic_istream<charT, Traits>&
operator>>(basic_istream<charT, Traits>& is,
time_point<high_resolution_clock, Duration>& tp);
} // chrono
} // std
*/
#include <chrono>
#include <beast/chrono/ratio_io.h>
//_LIBCPP_BEGIN_NAMESPACE_STD
namespace std {
namespace chrono
{
template <class To, class Rep, class Period>
To
round(const duration<Rep, Period>& d)
{
To t0 = duration_cast<To>(d);
To t1 = t0;
++t1;
typedef typename common_type<To, duration<Rep, Period> >::type _D;
_D diff0 = d - t0;
_D diff1 = t1 - d;
if (diff0 == diff1)
{
if (t0.count() & 1)
return t1;
return t0;
}
else if (diff0 < diff1)
return t0;
return t1;
}
enum duration_style {prefix, symbol};
enum timezone {utc, local};
class durationpunct
: public locale::facet
{
private:
duration_style __style_;
public:
static locale::id id;
explicit durationpunct(size_t refs = 0)
: locale::facet(refs), __style_(prefix) {}
explicit durationpunct(duration_style fmt, size_t refs = 0)
: locale::facet(refs), __style_(fmt) {}
bool is_symbol_name() const noexcept {return __style_ == symbol;}
bool is_prefix_name() const noexcept {return __style_ == prefix;}
};
class duration_fmt
{
duration_style form_;
public:
explicit duration_fmt(duration_style f) noexcept : form_(f) {}
// VFALCO NOTE disabled this for MSVC
/*explicit*/
operator duration_style() const noexcept {return form_;}
};
template<class charT, class traits>
basic_ostream<charT, traits>&
operator <<(basic_ostream<charT, traits>& os, duration_fmt d)
{
os.imbue(locale(os.getloc(), new durationpunct(static_cast<duration_style>(d))));
return os;
}
template<class charT, class traits>
basic_istream<charT, traits>&
operator >>(basic_istream<charT, traits>& is, duration_fmt d)
{
is.imbue(locale(is.getloc(), new durationpunct(static_cast<duration_style>(d))));
return is;
}
template <class _CharT, class _Rep, class _Period>
basic_string<_CharT>
__get_unit(bool __is_long, const duration<_Rep, _Period>& d)
{
if (__is_long)
{
_CharT __p[] = {'s', 'e', 'c', 'o', 'n', 'd', 's', 0};
basic_string<_CharT> s = ratio_string<_Period, _CharT>::prefix() + __p;
if (d.count() == 1 || d.count() == -1)
s.pop_back();
return s;
}
return ratio_string<_Period, _CharT>::symbol() + 's';
}
template <class _CharT, class _Rep>
basic_string<_CharT>
__get_unit(bool __is_long, const duration<_Rep, ratio<1> >& d)
{
if (__is_long)
{
_CharT __p[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'};
basic_string<_CharT> s = basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT));
if (d.count() == 1 || d.count() == -1)
s.pop_back();
return s;
}
return basic_string<_CharT>(1, 's');
}
template <class _CharT, class _Rep>
basic_string<_CharT>
__get_unit(bool __is_long, const duration<_Rep, ratio<60> >& d)
{
if (__is_long)
{
_CharT __p[] = {'m', 'i', 'n', 'u', 't', 'e', 's'};
basic_string<_CharT> s = basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT));
if (d.count() == 1 || d.count() == -1)
s.pop_back();
return s;
}
_CharT __p[] = {'m', 'i', 'n'};
return basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT));
}
template <class _CharT, class _Rep>
basic_string<_CharT>
__get_unit(bool __is_long, const duration<_Rep, ratio<3600> >& d)
{
if (__is_long)
{
_CharT __p[] = {'h', 'o', 'u', 'r', 's'};
basic_string<_CharT> s = basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT));
if (d.count() == 1 || d.count() == -1)
s.pop_back();
return s;
}
return basic_string<_CharT>(1, 'h');
}
template <class _CharT, class _Traits, class _Rep, class _Period>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const duration<_Rep, _Period>& __d)
{
typename basic_ostream<_CharT, _Traits>::sentry ok(__os);
if (ok)
{
typedef durationpunct _F;
typedef basic_string<_CharT> string_type;
bool failed = false;
try
{
bool __is_long = true;
locale __loc = __os.getloc();
if (has_facet<_F>(__loc))
{
const _F& f = use_facet<_F>(__loc);
__is_long = f.is_prefix_name();
}
string_type __unit = __get_unit<_CharT>(__is_long, __d);
__os << __d.count() << ' ' << __unit;
}
catch (...)
{
failed = true;
}
if (failed)
__os.setstate(ios_base::failbit | ios_base::badbit);
}
return __os;
}
template <class _Rep, bool = is_scalar<_Rep>::value>
struct __duration_io_intermediate
{
typedef _Rep type;
};
template <class _Rep>
struct __duration_io_intermediate<_Rep, true>
{
typedef typename conditional
<
is_floating_point<_Rep>::value,
long double,
typename conditional
<
is_signed<_Rep>::value,
long long,
unsigned long long
>::type
>::type type;
};
template <class T>
T
__gcd(T x, T y)
{
while (y != 0)
{
T old_x = x;
x = y;
y = old_x % y;
}
return x;
}
template <>
long double
inline
__gcd(long double, long double)
{
return 1;
}
template <class _CharT, class _Traits, class _Rep, class _Period>
basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __is, duration<_Rep, _Period>& __d)
{
// These are unused and generate warnings
//typedef basic_string<_CharT> string_type;
//typedef durationpunct _F;
typedef typename __duration_io_intermediate<_Rep>::type _IR;
_IR __r;
// read value into __r
__is >> __r;
if (__is.good())
{
// now determine unit
typedef istreambuf_iterator<_CharT, _Traits> _I;
_I __i(__is);
_I __e;
if (__i != __e && *__i == ' ') // mandatory ' ' after value
{
++__i;
if (__i != __e)
{
locale __loc = __is.getloc();
// unit is num / den (yet to be determined)
unsigned long long num = 0;
unsigned long long den = 0;
ios_base::iostate __err = ios_base::goodbit;
if (*__i == '[')
{
// parse [N/D]s or [N/D]seconds format
++__i;
_CharT __x;
__is >> num >> __x >> den;
if (!__is.good() || __x != '/')
{
__is.setstate(__is.failbit);
return __is;
}
__i = _I(__is);
if (*__i != ']')
{
__is.setstate(__is.failbit);
return __is;
}
++__i;
const basic_string<_CharT> __units[] =
{
__get_unit<_CharT>(true, seconds(2)),
__get_unit<_CharT>(true, seconds(1)),
__get_unit<_CharT>(false, seconds(1))
};
const basic_string<_CharT>* __k = __scan_keyword(__i, __e,
__units, __units + sizeof(__units)/sizeof(__units[0]),
use_facet<ctype<_CharT> >(__loc),
__err);
switch ((__k - __units) / 3)
{
case 0:
break;
default:
__is.setstate(__err);
return __is;
}
}
else
{
// parse SI name, short or long
const basic_string<_CharT> __units[] =
{
__get_unit<_CharT>(true, duration<_Rep, atto>(2)),
__get_unit<_CharT>(true, duration<_Rep, atto>(1)),
__get_unit<_CharT>(false, duration<_Rep, atto>(1)),
__get_unit<_CharT>(true, duration<_Rep, femto>(2)),
__get_unit<_CharT>(true, duration<_Rep, femto>(1)),
__get_unit<_CharT>(false, duration<_Rep, femto>(1)),
__get_unit<_CharT>(true, duration<_Rep, pico>(2)),
__get_unit<_CharT>(true, duration<_Rep, pico>(1)),
__get_unit<_CharT>(false, duration<_Rep, pico>(1)),
__get_unit<_CharT>(true, duration<_Rep, nano>(2)),
__get_unit<_CharT>(true, duration<_Rep, nano>(1)),
__get_unit<_CharT>(false, duration<_Rep, nano>(1)),
__get_unit<_CharT>(true, duration<_Rep, micro>(2)),
__get_unit<_CharT>(true, duration<_Rep, micro>(1)),
__get_unit<_CharT>(false, duration<_Rep, micro>(1)),
__get_unit<_CharT>(true, duration<_Rep, milli>(2)),
__get_unit<_CharT>(true, duration<_Rep, milli>(1)),
__get_unit<_CharT>(false, duration<_Rep, milli>(1)),
__get_unit<_CharT>(true, duration<_Rep, centi>(2)),
__get_unit<_CharT>(true, duration<_Rep, centi>(1)),
__get_unit<_CharT>(false, duration<_Rep, centi>(1)),
__get_unit<_CharT>(true, duration<_Rep, deci>(2)),
__get_unit<_CharT>(true, duration<_Rep, deci>(1)),
__get_unit<_CharT>(false, duration<_Rep, deci>(1)),
__get_unit<_CharT>(true, duration<_Rep, deca>(2)),
__get_unit<_CharT>(true, duration<_Rep, deca>(1)),
__get_unit<_CharT>(false, duration<_Rep, deca>(1)),
__get_unit<_CharT>(true, duration<_Rep, hecto>(2)),
__get_unit<_CharT>(true, duration<_Rep, hecto>(1)),
__get_unit<_CharT>(false, duration<_Rep, hecto>(1)),
__get_unit<_CharT>(true, duration<_Rep, kilo>(2)),
__get_unit<_CharT>(true, duration<_Rep, kilo>(1)),
__get_unit<_CharT>(false, duration<_Rep, kilo>(1)),
__get_unit<_CharT>(true, duration<_Rep, mega>(2)),
__get_unit<_CharT>(true, duration<_Rep, mega>(1)),
__get_unit<_CharT>(false, duration<_Rep, mega>(1)),
__get_unit<_CharT>(true, duration<_Rep, giga>(2)),
__get_unit<_CharT>(true, duration<_Rep, giga>(1)),
__get_unit<_CharT>(false, duration<_Rep, giga>(1)),
__get_unit<_CharT>(true, duration<_Rep, tera>(2)),
__get_unit<_CharT>(true, duration<_Rep, tera>(1)),
__get_unit<_CharT>(false, duration<_Rep, tera>(1)),
__get_unit<_CharT>(true, duration<_Rep, peta>(2)),
__get_unit<_CharT>(true, duration<_Rep, peta>(1)),
__get_unit<_CharT>(false, duration<_Rep, peta>(1)),
__get_unit<_CharT>(true, duration<_Rep, exa>(2)),
__get_unit<_CharT>(true, duration<_Rep, exa>(1)),
__get_unit<_CharT>(false, duration<_Rep, exa>(1)),
__get_unit<_CharT>(true, duration<_Rep, ratio<1> >(2)),
__get_unit<_CharT>(true, duration<_Rep, ratio<1> >(1)),
__get_unit<_CharT>(false, duration<_Rep, ratio<1> >(1)),
__get_unit<_CharT>(true, duration<_Rep, ratio<60> >(2)),
__get_unit<_CharT>(true, duration<_Rep, ratio<60> >(1)),
__get_unit<_CharT>(false, duration<_Rep, ratio<60> >(1)),
__get_unit<_CharT>(true, duration<_Rep, ratio<3600> >(2)),
__get_unit<_CharT>(true, duration<_Rep, ratio<3600> >(1)),
__get_unit<_CharT>(false, duration<_Rep, ratio<3600> >(1))
};
const basic_string<_CharT>* __k = __scan_keyword(__i, __e,
__units, __units + sizeof(__units)/sizeof(__units[0]),
use_facet<ctype<_CharT> >(__loc),
__err);
switch (__k - __units)
{
case 0:
case 1:
case 2:
num = 1ULL;
den = 1000000000000000000ULL;
break;
case 3:
case 4:
case 5:
num = 1ULL;
den = 1000000000000000ULL;
break;
case 6:
case 7:
case 8:
num = 1ULL;
den = 1000000000000ULL;
break;
case 9:
case 10:
case 11:
num = 1ULL;
den = 1000000000ULL;
break;
case 12:
case 13:
case 14:
num = 1ULL;
den = 1000000ULL;
break;
case 15:
case 16:
case 17:
num = 1ULL;
den = 1000ULL;
break;
case 18:
case 19:
case 20:
num = 1ULL;
den = 100ULL;
break;
case 21:
case 22:
case 23:
num = 1ULL;
den = 10ULL;
break;
case 24:
case 25:
case 26:
num = 10ULL;
den = 1ULL;
break;
case 27:
case 28:
case 29:
num = 100ULL;
den = 1ULL;
break;
case 30:
case 31:
case 32:
num = 1000ULL;
den = 1ULL;
break;
case 33:
case 34:
case 35:
num = 1000000ULL;
den = 1ULL;
break;
case 36:
case 37:
case 38:
num = 1000000000ULL;
den = 1ULL;
break;
case 39:
case 40:
case 41:
num = 1000000000000ULL;
den = 1ULL;
break;
case 42:
case 43:
case 44:
num = 1000000000000000ULL;
den = 1ULL;
break;
case 45:
case 46:
case 47:
num = 1000000000000000000ULL;
den = 1ULL;
break;
case 48:
case 49:
case 50:
num = 1;
den = 1;
break;
case 51:
case 52:
case 53:
num = 60;
den = 1;
break;
case 54:
case 55:
case 56:
num = 3600;
den = 1;
break;
default:
__is.setstate(__err);
return __is;
}
}
// unit is num/den
// __r should be multiplied by (num/den) / _Period
// Reduce (num/den) / _Period to lowest terms
unsigned long long __gcd_n1_n2 = __gcd<unsigned long long>(num, _Period::num);
unsigned long long __gcd_d1_d2 = __gcd<unsigned long long>(den, _Period::den);
num /= __gcd_n1_n2;
den /= __gcd_d1_d2;
unsigned long long __n2 = _Period::num / __gcd_n1_n2;
unsigned long long __d2 = _Period::den / __gcd_d1_d2;
if (num > numeric_limits<unsigned long long>::max() / __d2 ||
den > numeric_limits<unsigned long long>::max() / __n2)
{
// (num/den) / _Period overflows
__is.setstate(__is.failbit);
return __is;
}
num *= __d2;
den *= __n2;
// num / den is now factor to multiply by __r
typedef typename common_type<_IR, unsigned long long>::type _CT;
if (is_integral<_IR>::value)
{
// Reduce __r * num / den
_CT __t = __gcd<_CT>(__r, den);
__r /= __t;
den /= __t;
if (den != 1)
{
// Conversion to _Period is integral and not exact
__is.setstate(__is.failbit);
return __is;
}
}
if (__r > duration_values<_CT>::max() / num)
{
// Conversion to _Period overflowed
__is.setstate(__is.failbit);
return __is;
}
_CT __t = __r * num;
__t /= den;
if (duration_values<_Rep>::max() < __t)
{
// Conversion to _Period overflowed
__is.setstate(__is.failbit);
return __is;
}
// Success! Store it.
__r = _Rep(__t);
__d = duration<_Rep, _Period>(__r);
__is.setstate(__err);
}
else
__is.setstate(__is.failbit | __is.eofbit);
}
else
{
if (__i == __e)
__is.setstate(__is.eofbit);
__is.setstate(__is.failbit);
}
}
else
__is.setstate(__is.failbit);
return __is;
}
template <class charT>
class timepunct
: public locale::facet
{
public:
typedef basic_string<charT> string_type;
private:
string_type fmt_;
chrono::timezone tz_;
public:
static locale::id id;
explicit timepunct(size_t refs = 0)
: locale::facet(refs), tz_(utc) {}
timepunct(timezone tz, string_type fmt, size_t refs = 0)
: locale::facet(refs), fmt_(std::move(fmt)), tz_(tz) {}
const string_type& fmt() const noexcept {return fmt_;}
chrono::timezone get_timezone() const noexcept {return tz_;}
};
template <class CharT>
locale::id
timepunct<CharT>::id;
template <class _CharT, class _Traits, class _Duration>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os,
const time_point<steady_clock, _Duration>& __tp)
{
return __os << __tp.time_since_epoch() << " since boot";
}
template<class charT>
struct __time_manip
{
basic_string<charT> fmt_;
timezone tz_;
__time_manip(timezone tz, basic_string<charT> fmt)
: fmt_(std::move(fmt)),
tz_(tz) {}
};
template<class charT, class traits>
basic_ostream<charT, traits>&
operator <<(basic_ostream<charT, traits>& os, __time_manip<charT> m)
{
os.imbue(locale(os.getloc(), new timepunct<charT>(m.tz_, std::move(m.fmt_))));
return os;
}
template<class charT, class traits>
basic_istream<charT, traits>&
operator >>(basic_istream<charT, traits>& is, __time_manip<charT> m)
{
is.imbue(locale(is.getloc(), new timepunct<charT>(m.tz_, std::move(m.fmt_))));
return is;
}
template<class charT>
inline
__time_manip<charT>
time_fmt(timezone tz, const charT* fmt)
{
return __time_manip<charT>(tz, fmt);
}
template<class charT>
inline
__time_manip<charT>
time_fmt(timezone tz, basic_string<charT> fmt)
{
return __time_manip<charT>(tz, std::move(fmt));
}
class __time_man
{
timezone form_;
public:
explicit __time_man(timezone f) : form_(f) {}
// explicit
operator timezone() const {return form_;}
};
template<class charT, class traits>
basic_ostream<charT, traits>&
operator <<(basic_ostream<charT, traits>& os, __time_man m)
{
os.imbue(locale(os.getloc(), new timepunct<charT>(static_cast<timezone>(m), basic_string<charT>())));
return os;
}
template<class charT, class traits>
basic_istream<charT, traits>&
operator >>(basic_istream<charT, traits>& is, __time_man m)
{
is.imbue(locale(is.getloc(), new timepunct<charT>(static_cast<timezone>(m), basic_string<charT>())));
return is;
}
inline
__time_man
time_fmt(timezone f)
{
return __time_man(f);
}
} // chrono
}
#endif

View File

@@ -23,6 +23,7 @@
// From Howard Hinnant // From Howard Hinnant
// http://home.roadrunner.com/~hinnant/duration_io/chrono_util.html // http://home.roadrunner.com/~hinnant/duration_io/chrono_util.html
#if !defined(_MSC_FULL_VER) || (_MSC_FULL_VER <= 190023506)
// round down // round down
template <class To, class Rep, class Period> template <class To, class Rep, class Period>
To floor(std::chrono::duration <Rep, Period> const& d) To floor(std::chrono::duration <Rep, Period> const& d)
@@ -62,5 +63,6 @@ To ceil (std::chrono::duration <Rep, Period> const& d)
++t; ++t;
return t; return t;
} }
#endif
#endif #endif

View File

@@ -23,16 +23,6 @@
#include <beast/chrono/RelativeTime.h> #include <beast/chrono/RelativeTime.h>
// VFALCO TODO Migrate the localizable strings interfaces for this file
#ifndef NEEDS_TRANS
#define NEEDS_TRANS(s) (s)
#endif
#ifndef TRANS
#define TRANS(s) (s)
#endif
namespace beast { namespace beast {
RelativeTime::RelativeTime (const RelativeTime::value_type secs) noexcept RelativeTime::RelativeTime (const RelativeTime::value_type secs) noexcept
@@ -175,86 +165,6 @@ bool operator<= (RelativeTime t1, RelativeTime t2) noexcept
return t1.inSeconds() <= t2.inSeconds(); return t1.inSeconds() <= t2.inSeconds();
} }
//==============================================================================
static void translateTimeField (String& result, int n, const char* singular, const char* plural)
{
result << TRANS (String((n == 1) ? singular : plural))
.replace (n == 1 ? "1" : "2", String (n))
<< ' ';
}
String RelativeTime::getDescription (const String& returnValueForZeroTime) const
{
if (numSeconds < 0.001 && numSeconds > -0.001)
return returnValueForZeroTime;
String result;
result.preallocateBytes (32);
if (numSeconds < 0)
result << '-';
int fieldsShown = 0;
int n = std::abs ((int) inWeeks());
if (n > 0)
{
translateTimeField (result, n, NEEDS_TRANS("1 week"), NEEDS_TRANS("2 weeks"));
++fieldsShown;
}
n = std::abs ((int) inDays()) % 7;
if (n > 0)
{
translateTimeField (result, n, NEEDS_TRANS("1 day"), NEEDS_TRANS("2 days"));
++fieldsShown;
}
if (fieldsShown < 2)
{
n = std::abs ((int) inHours()) % 24;
if (n > 0)
{
translateTimeField (result, n, NEEDS_TRANS("1 hour"), NEEDS_TRANS("2 hours"));
++fieldsShown;
}
if (fieldsShown < 2)
{
n = std::abs ((int) inMinutes()) % 60;
if (n > 0)
{
translateTimeField (result, n, NEEDS_TRANS("1 minute"), NEEDS_TRANS("2 minutes"));
++fieldsShown;
}
if (fieldsShown < 2)
{
n = std::abs ((int) inSeconds()) % 60;
if (n > 0)
{
translateTimeField (result, n, NEEDS_TRANS("1 seconds"), NEEDS_TRANS("2 seconds"));
++fieldsShown;
}
if (fieldsShown == 0)
{
n = std::abs ((int) inMilliseconds()) % 1000;
if (n > 0)
result << n << ' ' << TRANS ("ms");
}
}
}
}
return result.trimEnd();
}
std::string RelativeTime::to_string () const
{
return getDescription ().toStdString();
}
} }
#if BEAST_WINDOWS #if BEAST_WINDOWS

View File

@@ -1,41 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// chrono_io
//
// (C) Copyright Howard Hinnant
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt).
#include <beast/chrono/chrono_io.h>
//_LIBCPP_BEGIN_NAMESPACE_STD
namespace std {
namespace chrono
{
locale::id
durationpunct::id;
} // chrono
//_LIBCPP_END_NAMESPACE_STD
}

View File

@@ -42,9 +42,9 @@ public:
std::stringstream ss; std::stringstream ss;
ss << ss <<
"t1= " << t1.time_since_epoch() << "t1= " << t1.time_since_epoch().count() <<
", t2= " << t2.time_since_epoch() << ", t2= " << t2.time_since_epoch().count() <<
", elapsed= " << (t2 - t1); ", elapsed= " << (t2 - t1).count();
log << ss.str(); log << ss.str();
} }
} }
@@ -56,13 +56,13 @@ public:
std::stringstream ss; std::stringstream ss;
ss << "now() = " << c.now().time_since_epoch() << std::endl; ss << "now() = " << c.now().time_since_epoch().count() << std::endl;
c.set (clock_type::time_point (std::chrono::seconds(1))); c.set (clock_type::time_point (std::chrono::seconds(1)));
ss << "now() = " << c.now().time_since_epoch() << std::endl; ss << "now() = " << c.now().time_since_epoch().count() << std::endl;
c.set (clock_type::time_point (std::chrono::seconds(2))); c.set (clock_type::time_point (std::chrono::seconds(2)));
ss << "now() = " << c.now().time_since_epoch() << std::endl; ss << "now() = " << c.now().time_since_epoch().count() << std::endl;
log << ss.str(); log << ss.str();
} }

View File

@@ -50,107 +50,6 @@
# define BEAST_CONSTEXPR constexpr # define BEAST_CONSTEXPR constexpr
#endif #endif
// Debugging and assertion macros
#if BEAST_LOG_ASSERTIONS || BEAST_DEBUG
#define beast_LogCurrentAssertion beast::logAssertion (__FILE__, __LINE__);
#else
#define beast_LogCurrentAssertion
#endif
#if BEAST_IOS || BEAST_LINUX || BEAST_ANDROID || BEAST_PPC
/** This will try to break into the debugger if the app is currently being debugged.
If called by an app that's not being debugged, the behaiour isn't defined - it may crash or not, depending
on the platform.
@see bassert()
*/
# define beast_breakDebugger { ::kill (0, SIGTRAP); }
#elif BEAST_USE_INTRINSICS
# ifndef __INTEL_COMPILER
# pragma intrinsic (__debugbreak)
# endif
# define beast_breakDebugger { __debugbreak(); }
#elif BEAST_GCC || BEAST_MAC
# if BEAST_NO_INLINE_ASM
# define beast_breakDebugger { }
# else
# define beast_breakDebugger { asm ("int $3"); }
# endif
#else
# define beast_breakDebugger { __asm int 3 }
#endif
#if BEAST_CLANG && defined (__has_feature) && ! defined (BEAST_ANALYZER_NORETURN)
# if __has_feature (attribute_analyzer_noreturn)
inline void __attribute__((analyzer_noreturn)) beast_assert_noreturn() {}
# define BEAST_ANALYZER_NORETURN beast_assert_noreturn();
# endif
#endif
#ifndef BEAST_ANALYZER_NORETURN
#define BEAST_ANALYZER_NORETURN
#endif
//------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
/** Report a fatal error message and terminate the application.
Normally you won't call this directly.
*/
extern void beast_reportFatalError (char const* message, char const* fileName, int lineNumber);
#ifdef __cplusplus
}
#endif
#if BEAST_DEBUG || DOXYGEN
/** Writes a string to the standard error stream.
This is only compiled in a debug build.
*/
#define BDBG(dbgtext) { \
beast::String tempDbgBuf; \
tempDbgBuf << dbgtext; \
beast::outputDebugString (tempDbgBuf.toStdString ()); \
}
#if 0
/** This will always cause an assertion failure.
It is only compiled in a debug build, (unless BEAST_LOG_ASSERTIONS is enabled for your build).
@see bassert
*/
#define bassertfalse { beast_LogCurrentAssertion; if (beast::beast_isRunningUnderDebugger()) beast_breakDebugger; BEAST_ANALYZER_NORETURN }
/** Platform-independent assertion macro.
This macro gets turned into a no-op when you're building with debugging turned off, so be
careful that the expression you pass to it doesn't perform any actions that are vital for the
correct behaviour of your program!
@see bassertfalse
*/
#define bassert(expression) { if (! (expression)) beast_reportFatalError(#expression,__FILE__,__LINE__); }
#else
#define bassertfalse assert(false)
#define bassert(expression) assert(expression)
#endif
#else
// If debugging is disabled, these dummy debug and assertion macros are used..
#define BDBG(dbgtext)
#define bassertfalse { beast_LogCurrentAssertion }
# if BEAST_LOG_ASSERTIONS
# define bassert(expression) { if (! (expression)) bassertfalse; }
# else
# define bassert(a) {}
# endif
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if ! DOXYGEN #if ! DOXYGEN
@@ -195,17 +94,6 @@ extern void beast_reportFatalError (char const* message, char const* fileName, i
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if BEAST_ANDROID && ! DOXYGEN
# define BEAST_MODAL_LOOPS_PERMITTED 0
#elif ! defined (BEAST_MODAL_LOOPS_PERMITTED)
/** Some operating environments don't provide a modal loop mechanism, so this
flag can be used to disable any functions that try to run a modal loop.
*/
#define BEAST_MODAL_LOOPS_PERMITTED 1
#endif
//------------------------------------------------------------------------------
#if BEAST_GCC #if BEAST_GCC
# define BEAST_PACKED __attribute__((packed)) # define BEAST_PACKED __attribute__((packed))
#elif ! DOXYGEN #elif ! DOXYGEN
@@ -260,11 +148,4 @@ extern void beast_reportFatalError (char const* message, char const* fileName, i
# define BEAST_MOVE_CAST(type) type # define BEAST_MOVE_CAST(type) type
#endif #endif
#ifdef __cplusplus
namespace beast {
bool beast_isRunningUnderDebugger();
void logAssertion (char const* file, int line);
}
#endif
#endif #endif

View File

@@ -1,86 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CONFIG_CONTRACTCHECKS_H_INCLUDED
#define BEAST_CONFIG_CONTRACTCHECKS_H_INCLUDED
// This file has to work when included in a C source file.
#if defined (fatal_error) || \
defined (fatal_condition) || \
defined (meets_condition) || \
defined (meets_precondition) || \
defined (meets_postcondition) || \
defined (meets_invariant) || \
defined (check_invariant)
#error "Programming by contract macros cannot be overriden!"
#endif
/** Report a fatal error message and terminate the application.
This macro automatically fills in the file and line number
Meets this declaration syntax:
@code inline void fatal_error (char const* message); @endif
@see FatalError
*/
#define fatal_error(message) beast_reportFatalError (message, __FILE__, __LINE__)
/** Reports a fatal error message type if the condition is false
The condition is always evaluated regardless of settings.
Meets this declaration syntax:
@code inline void fatal_condition (bool condition, char const* category); @endcode
*/
#define fatal_condition(condition,category) static_cast <void> \
(((!!(condition)) || (beast_reportFatalError ( \
category " '" BEAST_STRINGIFY(condition) "' failed.", __FILE__, __LINE__), 0)))
/** Reports a fatal error message type if the condition is false
The condition is always evaluated regardless of settings.
Meets this declaration syntax:
@code inline void fatal_condition (bool condition, char const* category); @endcode
*/
#define meets_condition(condition,category) static_cast <bool> \
(((!!(condition)) || (beast_reportFatalError ( \
category " '" BEAST_STRINGIFY(condition) "' failed.", __FILE__, __LINE__), false)))
/** Condition tests for programming by contract.
The condition is always evaluated regardless of settings, and gets returned.
Meets this declaration syntax:
@code inline bool meets_condition (bool); @endcode
*/
/** @{ */
#define meets_precondition(condition) meets_condition(condition,"Pre-condition")
#define meets_postcondition(condition) meets_condition(condition,"Post-condition")
#define meets_invariant(condition) meets_condition(condition,"Invariant")
/** @} */
/** Condition tests for programming by contract.
The condition is evaluated only if BEAST_DISABLE_CONTRACT_CHECKS is 0.
Meets this declaration syntax:
@code inline void check_condition (bool); @endcode
@see BEAST_DISABLE_CONTRACT_CHECKS
*/
/** @{ */
#if ! BEAST_DISABLE_CONTRACT_CHECKS
# define check_invariant(condition) meets_invariant(condition)
#else
# define check_invariant(condition) ((void)0)
#endif
/** @} */
#endif

View File

@@ -199,9 +199,7 @@ private:
, public std::binary_function <Key, element, bool> , public std::binary_function <Key, element, bool>
{ {
public: public:
KeyValueCompare () KeyValueCompare () = default;
{
}
KeyValueCompare (Compare const& compare) KeyValueCompare (Compare const& compare)
: empty_base_optimization <Compare> (compare) : empty_base_optimization <Compare> (compare)
@@ -234,6 +232,11 @@ private:
return this->member() (extract (e.value), k); return this->member() (extract (e.value), k);
} }
bool operator() (element const& x, element const& y) const
{
return this->member() (extract (x.value), extract (y.value));
}
Compare& compare() Compare& compare()
{ {
return empty_base_optimization <Compare>::member(); return empty_base_optimization <Compare>::member();
@@ -251,10 +254,12 @@ private:
using cont_type = typename std::conditional < using cont_type = typename std::conditional <
IsMulti, IsMulti,
typename boost::intrusive::make_multiset <element, typename boost::intrusive::make_multiset <element,
boost::intrusive::constant_time_size <true> boost::intrusive::constant_time_size <true>,
boost::intrusive::compare<KeyValueCompare>
>::type, >::type,
typename boost::intrusive::make_set <element, typename boost::intrusive::make_set <element,
boost::intrusive::constant_time_size <true> boost::intrusive::constant_time_size <true>,
boost::intrusive::compare<KeyValueCompare>
>::type >::type
>::type; >::type;
@@ -1254,6 +1259,7 @@ aged_ordered_container (
clock_type& clock, clock_type& clock,
Compare const& comp) Compare const& comp)
: m_config (clock, comp) : m_config (clock, comp)
, m_cont (comp)
{ {
} }
@@ -1275,6 +1281,7 @@ aged_ordered_container (
Compare const& comp, Compare const& comp,
Allocator const& alloc) Allocator const& alloc)
: m_config (clock, comp, alloc) : m_config (clock, comp, alloc)
, m_cont (comp)
{ {
} }
@@ -1297,6 +1304,7 @@ aged_ordered_container (InputIt first, InputIt last,
clock_type& clock, clock_type& clock,
Compare const& comp) Compare const& comp)
: m_config (clock, comp) : m_config (clock, comp)
, m_cont (comp)
{ {
insert (first, last); insert (first, last);
} }
@@ -1322,6 +1330,7 @@ aged_ordered_container (InputIt first, InputIt last,
Compare const& comp, Compare const& comp,
Allocator const& alloc) Allocator const& alloc)
: m_config (clock, comp, alloc) : m_config (clock, comp, alloc)
, m_cont (comp)
{ {
insert (first, last); insert (first, last);
} }
@@ -1331,6 +1340,7 @@ template <bool IsMulti, bool IsMap, class Key, class T,
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>:: aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
aged_ordered_container (aged_ordered_container const& other) aged_ordered_container (aged_ordered_container const& other)
: m_config (other.m_config) : m_config (other.m_config)
, m_cont (other.m_cont.comp())
{ {
insert (other.cbegin(), other.cend()); insert (other.cbegin(), other.cend());
} }
@@ -1341,6 +1351,7 @@ aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
aged_ordered_container (aged_ordered_container const& other, aged_ordered_container (aged_ordered_container const& other,
Allocator const& alloc) Allocator const& alloc)
: m_config (other.m_config, alloc) : m_config (other.m_config, alloc)
, m_cont (other.m_cont.comp())
{ {
insert (other.cbegin(), other.cend()); insert (other.cbegin(), other.cend());
} }
@@ -1361,6 +1372,7 @@ aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
aged_ordered_container (aged_ordered_container&& other, aged_ordered_container (aged_ordered_container&& other,
Allocator const& alloc) Allocator const& alloc)
: m_config (std::move (other.m_config), alloc) : m_config (std::move (other.m_config), alloc)
, m_cont (std::move(other.m_cont.comp()))
{ {
insert (other.cbegin(), other.cend()); insert (other.cbegin(), other.cend());
other.clear (); other.clear ();
@@ -1383,6 +1395,7 @@ aged_ordered_container (std::initializer_list <value_type> init,
clock_type& clock, clock_type& clock,
Compare const& comp) Compare const& comp)
: m_config (clock, comp) : m_config (clock, comp)
, m_cont (comp)
{ {
insert (init.begin(), init.end()); insert (init.begin(), init.end());
} }
@@ -1406,6 +1419,7 @@ aged_ordered_container (std::initializer_list <value_type> init,
Compare const& comp, Compare const& comp,
Allocator const& alloc) Allocator const& alloc)
: m_config (clock, comp, alloc) : m_config (clock, comp, alloc)
, m_cont (comp)
{ {
insert (init.begin(), init.end()); insert (init.begin(), init.end());
} }

View File

@@ -39,9 +39,11 @@ public:
static beast::endian const endian = static beast::endian const endian =
beast::endian::native; beast::endian::native;
static std::size_t const digest_size =
Context::digest_size;
using result_type = using result_type =
std::array<std::uint8_t, std::array<std::uint8_t, digest_size>;
Context::digest_size>;
mac_facade() noexcept mac_facade() noexcept
{ {

View File

@@ -23,8 +23,8 @@
#include <beast/container/fnv1a.h> #include <beast/container/fnv1a.h>
#include <beast/container/siphash.h> #include <beast/container/siphash.h>
#include <beast/container/xxhasher.h> #include <beast/container/xxhasher.h>
#include <beast/random/rngfill.h> #include <beast/rngfill.h>
#include <beast/random/xor_shift_engine.h> #include <beast/xor_shift_engine.h>
#include <beast/unit_test/suite.h> #include <beast/unit_test/suite.h>
#include <array> #include <array>
#include <chrono> #include <chrono>

View File

@@ -24,7 +24,7 @@
#include <beast/hash/endian.h> #include <beast/hash/endian.h>
#include <beast/hash/tests/hash_metrics.h> #include <beast/hash/tests/hash_metrics.h>
#include <beast/hash/hash_append.h> #include <beast/hash/hash_append.h>
#include <beast/chrono/chrono_io.h> #include <beast/xor_shift_engine.h>
#include <beast/unit_test/suite.h> #include <beast/unit_test/suite.h>
#include <beast/utility/type_name.h> #include <beast/utility/type_name.h>
#include <array> #include <array>
@@ -284,7 +284,7 @@ private:
public: public:
SlowKey() SlowKey()
{ {
static std::mt19937_64 eng; static beast::xor_shift_engine eng;
std::uniform_int_distribution<short> yeardata(1900, 2014); std::uniform_int_distribution<short> yeardata(1900, 2014);
std::uniform_int_distribution<unsigned> monthdata(1, 12); std::uniform_int_distribution<unsigned> monthdata(1, 12);
std::uniform_int_distribution<unsigned> daydata(1, 28); std::uniform_int_distribution<unsigned> daydata(1, 28);
@@ -331,8 +331,7 @@ private:
public: public:
FastKey() FastKey()
{ {
static std::conditional_t <sizeof(std::size_t)==sizeof(std::uint64_t), static beast::xor_shift_engine eng;
std::mt19937_64, std::mt19937> eng;
for (auto& v : m_values) for (auto& v : m_values)
v = eng(); v = eng();
} }

View File

@@ -166,15 +166,15 @@ windowed_score (FwdIter first, FwdIter last)
int maxwidth = 20; int maxwidth = 20;
// We need at least 5 keys per bin to reliably test distribution biases // We need at least 5 keys per bin to reliably test distribution biases
// down to 1%, so don't bother to test sparser distributions than that // down to 1%, so don't bother to test sparser distributions than that
while (static_cast<double>(size) / (1 << maxwidth) < 5.0) while (static_cast<double>(size) / (1ull << maxwidth) < 5.0)
maxwidth--; maxwidth--;
double worst = 0; double worst = 0;
std::vector <int> bins (1 << maxwidth); std::vector <int> bins (1ull << maxwidth);
int const hashbits = sizeof(std::size_t) * CHAR_BIT; int const hashbits = sizeof(std::size_t) * CHAR_BIT;
for (int start = 0; start < hashbits; ++start) for (int start = 0; start < hashbits; ++start)
{ {
int width = maxwidth; int width = maxwidth;
bins.assign (1 << width, 0); bins.assign (1ull << width, 0);
for (auto iter (first); iter != last; ++iter) for (auto iter (first); iter != last; ++iter)
++bins[detail::window(&*iter, start, width)]; ++bins[detail::window(&*iter, start, width)];
// Test the distribution, then fold the bins in half, // Test the distribution, then fold the bins in half,

View File

@@ -23,9 +23,8 @@
#include <beast/hash/fnv1a.h> #include <beast/hash/fnv1a.h>
#include <beast/hash/siphash.h> #include <beast/hash/siphash.h>
#include <beast/hash/xxhasher.h> #include <beast/hash/xxhasher.h>
#include <beast/chrono/chrono_io.h> #include <beast/rngfill.h>
#include <beast/random/rngfill.h> #include <beast/xor_shift_engine.h>
#include <beast/random/xor_shift_engine.h>
#include <beast/unit_test/suite.h> #include <beast/unit_test/suite.h>
#include <array> #include <array>
#include <chrono> #include <chrono>
@@ -61,7 +60,7 @@ public:
} }
auto const elapsed = clock_type::now() - start; auto const elapsed = clock_type::now() - start;
log << setw(12) << what << " " << log << setw(12) << what << " " <<
duration<double>(elapsed) << "s"; duration<double>(elapsed).count() << "s";
} }
void void

View File

@@ -24,7 +24,6 @@
#include <beast/http/impl/basic_parser.cpp> #include <beast/http/impl/basic_parser.cpp>
#include <beast/http/impl/joyent_parser.cpp> #include <beast/http/impl/joyent_parser.cpp>
#include <beast/http/impl/method.cpp> #include <beast/http/impl/method.cpp>
#include <beast/http/impl/raw_parser.cpp>
#include <beast/http/impl/URL.cpp> #include <beast/http/impl/URL.cpp>
#include <beast/http/tests/chunked_encoder.test.cpp> #include <beast/http/tests/chunked_encoder.test.cpp>

View File

@@ -74,6 +74,8 @@ private:
cb_t on_headers_complete; cb_t on_headers_complete;
data_cb_t on_body; data_cb_t on_body;
cb_t on_message_complete; cb_t on_message_complete;
cb_t on_chunk_header;
cb_t on_chunk_complete;
}; };
char state_ [sizeof(state_t)]; char state_ [sizeof(state_t)];
@@ -221,6 +223,8 @@ private:
int do_headers_complete (); int do_headers_complete ();
int do_body (char const* in, std::size_t bytes); int do_body (char const* in, std::size_t bytes);
int do_message_complete (); int do_message_complete ();
int do_chunk_header();
int do_chunk_complete();
static int cb_message_start (joyent::http_parser*); static int cb_message_start (joyent::http_parser*);
static int cb_url (joyent::http_parser*, char const*, std::size_t); static int cb_url (joyent::http_parser*, char const*, std::size_t);
@@ -230,6 +234,8 @@ private:
static int cb_headers_complete (joyent::http_parser*); static int cb_headers_complete (joyent::http_parser*);
static int cb_body (joyent::http_parser*, char const*, std::size_t); static int cb_body (joyent::http_parser*, char const*, std::size_t);
static int cb_message_complete (joyent::http_parser*); static int cb_message_complete (joyent::http_parser*);
static int cb_chunk_header (joyent::http_parser*);
static int cb_chunk_complete (joyent::http_parser*);
}; };
template <class ConstBufferSequence> template <class ConstBufferSequence>

View File

@@ -64,6 +64,9 @@ private:
template <class String> template <class String>
bool bool
operator() (element const& lhs, String const& rhs) const; operator() (element const& lhs, String const& rhs) const;
bool
operator() (element const& lhs, element const& rhs) const;
}; };
struct transform struct transform
@@ -81,7 +84,8 @@ private:
>::type; >::type;
using set_t = boost::intrusive::make_set <element, using set_t = boost::intrusive::make_set <element,
boost::intrusive::constant_time_size <true> boost::intrusive::constant_time_size <true>,
boost::intrusive::compare<less>
>::type; >::type;
list_t list_; list_t list_;
@@ -187,6 +191,14 @@ headers::less::operator() (
return beast::ci_less::operator() (lhs.data.first, rhs); return beast::ci_less::operator() (lhs.data.first, rhs);
} }
inline
bool
headers::less::operator() (
element const& lhs, element const& rhs) const
{
return beast::ci_less::operator() (lhs.data.first, rhs.data.first);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
inline inline

View File

@@ -93,6 +93,8 @@ basic_parser::basic_parser (bool request) noexcept
h->on_headers_complete = &basic_parser::cb_headers_complete; h->on_headers_complete = &basic_parser::cb_headers_complete;
h->on_body = &basic_parser::cb_body; h->on_body = &basic_parser::cb_body;
h->on_message_complete = &basic_parser::cb_message_complete; h->on_message_complete = &basic_parser::cb_message_complete;
h->on_chunk_header = &basic_parser::cb_chunk_header;
h->on_chunk_complete = &basic_parser::cb_chunk_complete;
joyent::http_parser_init (s, request joyent::http_parser_init (s, request
? joyent::http_parser_type::HTTP_REQUEST ? joyent::http_parser_type::HTTP_REQUEST
@@ -231,6 +233,18 @@ basic_parser::do_message_complete ()
return 0; return 0;
} }
int
basic_parser::do_chunk_header()
{
return 0;
}
int
basic_parser::do_chunk_complete()
{
return 0;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int int
@@ -295,5 +309,19 @@ basic_parser::cb_message_complete (joyent::http_parser* p)
p->data)->do_message_complete(); p->data)->do_message_complete();
} }
int
basic_parser::cb_chunk_header (joyent::http_parser* p)
{
return reinterpret_cast <basic_parser*> (
p->data)->do_chunk_header();
}
int
basic_parser::cb_chunk_complete (joyent::http_parser* p)
{
return reinterpret_cast <basic_parser*> (
p->data)->do_chunk_complete();
}
} // http } // http
} // beast } // beast

View File

@@ -5,12 +5,15 @@ tags
test test
test_g test_g
test_fast test_fast
bench
url_parser url_parser
parsertrace parsertrace
parsertrace_g parsertrace_g
*.mk *.mk
*.Makefile *.Makefile
*.so.* *.so.*
*.exe.*
*.exe
*.a *.a

View File

@@ -5,3 +5,4 @@ Salman Haq <salman.haq@asti-usa.com>
Simon Zimmermann <simonz05@gmail.com> Simon Zimmermann <simonz05@gmail.com>
Thomas LE ROUX <thomas@november-eleven.fr> LE ROUX Thomas <thomas@procheo.fr> Thomas LE ROUX <thomas@november-eleven.fr> LE ROUX Thomas <thomas@procheo.fr>
Thomas LE ROUX <thomas@november-eleven.fr> Thomas LE ROUX <thomas@procheo.fr> Thomas LE ROUX <thomas@november-eleven.fr> Thomas LE ROUX <thomas@procheo.fr>
Fedor Indutny <fedor@indutny.com>

View File

@@ -10,4 +10,4 @@ script:
notifications: notifications:
email: false email: false
irc: irc:
- "irc.freenode.net#libuv" - "irc.freenode.net#node-ci"

View File

@@ -39,11 +39,30 @@ BogDan Vatra <bogdan@kde.org>
Peter Faiman <peter@thepicard.org> Peter Faiman <peter@thepicard.org>
Corey Richardson <corey@octayn.net> Corey Richardson <corey@octayn.net>
Tóth Tamás <tomika_nospam@freemail.hu> Tóth Tamás <tomika_nospam@freemail.hu>
Patrik Stutz <patrik.stutz@gmail.com>
Cam Swords <cam.swords@gmail.com> Cam Swords <cam.swords@gmail.com>
Chris Dickinson <christopher.s.dickinson@gmail.com> Chris Dickinson <christopher.s.dickinson@gmail.com>
Uli Köhler <ukoehler@btronik.de> Uli Köhler <ukoehler@btronik.de>
Charlie Somerville <charlie@charliesomerville.com> Charlie Somerville <charlie@charliesomerville.com>
Patrik Stutz <patrik.stutz@gmail.com>
Fedor Indutny <fedor.indutny@gmail.com> Fedor Indutny <fedor.indutny@gmail.com>
runner <runner.mei@gmail.com> runner <runner.mei@gmail.com>
Alexis Campailla <alexis@janeasystems.com> Alexis Campailla <alexis@janeasystems.com>
David Wragg <david@wragg.org>
Vinnie Falco <vinnie.falco@gmail.com>
Alex Butum <alexbutum@linux.com>
Rex Feng <rexfeng@gmail.com>
Alex Kocharin <alex@kocharin.ru>
Mark Koopman <markmontymark@yahoo.com>
Helge Heß <me@helgehess.eu>
Alexis La Goutte <alexis.lagoutte@gmail.com>
George Miroshnykov <george.miroshnykov@gmail.com>
Maciej Małecki <me@mmalecki.com>
Marc O'Morain <github.com@marcomorain.com>
Jeff Pinner <jpinner@twitter.com>
Timothy J Fontaine <tjfontaine@gmail.com>
Akagi201 <akagi201@gmail.com>
Romain Giraud <giraud.romain@gmail.com>
Jay Satiro <raysatiro@yahoo.com>
Arne Steen <Arne.Steen@gmx.de>
Kjell Schubert <kjell.schubert@gmail.com>
Olivier Mengué <dolmen@cpan.org>

View File

@@ -1,4 +0,0 @@
Contributors must agree to the Contributor License Agreement before patches
can be accepted.
http://spreadsheets2.google.com/viewform?hl=en&formkey=dDJXOGUwbzlYaWM4cHN1MERwQS1CSnc6MQ

View File

@@ -19,32 +19,54 @@
# IN THE SOFTWARE. # IN THE SOFTWARE.
PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"')
SONAME ?= libhttp_parser.so.2.2.1 HELPER ?=
BINEXT ?=
ifeq (darwin,$(PLATFORM))
SONAME ?= libhttp_parser.2.6.1.dylib
SOEXT ?= dylib
else ifeq (wine,$(PLATFORM))
CC = winegcc
BINEXT = .exe.so
HELPER = wine
else
SONAME ?= libhttp_parser.so.2.6.1
SOEXT ?= so
endif
CC?=gcc CC?=gcc
AR?=ar AR?=ar
CPPFLAGS ?=
LDFLAGS ?=
CPPFLAGS += -I. CPPFLAGS += -I.
CPPFLAGS_DEBUG = $(CPPFLAGS) -DHTTP_PARSER_STRICT=1 CPPFLAGS_DEBUG = $(CPPFLAGS) -DHTTP_PARSER_STRICT=1
CPPFLAGS_DEBUG += $(CPPFLAGS_DEBUG_EXTRA) CPPFLAGS_DEBUG += $(CPPFLAGS_DEBUG_EXTRA)
CPPFLAGS_FAST = $(CPPFLAGS) -DHTTP_PARSER_STRICT=0 CPPFLAGS_FAST = $(CPPFLAGS) -DHTTP_PARSER_STRICT=0
CPPFLAGS_FAST += $(CPPFLAGS_FAST_EXTRA) CPPFLAGS_FAST += $(CPPFLAGS_FAST_EXTRA)
CPPFLAGS_BENCH = $(CPPFLAGS_FAST)
CFLAGS += -Wall -Wextra -Werror CFLAGS += -Wall -Wextra -Werror
CFLAGS_DEBUG = $(CFLAGS) -O0 -g $(CFLAGS_DEBUG_EXTRA) CFLAGS_DEBUG = $(CFLAGS) -O0 -g $(CFLAGS_DEBUG_EXTRA)
CFLAGS_FAST = $(CFLAGS) -O3 $(CFLAGS_FAST_EXTRA) CFLAGS_FAST = $(CFLAGS) -O3 $(CFLAGS_FAST_EXTRA)
CFLAGS_BENCH = $(CFLAGS_FAST) -Wno-unused-parameter
CFLAGS_LIB = $(CFLAGS_FAST) -fPIC CFLAGS_LIB = $(CFLAGS_FAST) -fPIC
LDFLAGS_LIB = $(LDFLAGS) -shared LDFLAGS_LIB = $(LDFLAGS) -shared
INSTALL ?= install
PREFIX ?= $(DESTDIR)/usr/local
LIBDIR = $(PREFIX)/lib
INCLUDEDIR = $(PREFIX)/include
ifneq (darwin,$(PLATFORM)) ifneq (darwin,$(PLATFORM))
# TODO(bnoordhuis) The native SunOS linker expects -h rather than -soname... # TODO(bnoordhuis) The native SunOS linker expects -h rather than -soname...
LDFLAGS_LIB += -Wl,-soname=$(SONAME) LDFLAGS_LIB += -Wl,-soname=$(SONAME)
endif endif
test: test_g test_fast test: test_g test_fast
./test_g $(HELPER) ./test_g$(BINEXT)
./test_fast $(HELPER) ./test_fast$(BINEXT)
test_g: http_parser_g.o test_g.o test_g: http_parser_g.o test_g.o
$(CC) $(CFLAGS_DEBUG) $(LDFLAGS) http_parser_g.o test_g.o -o $@ $(CC) $(CFLAGS_DEBUG) $(LDFLAGS) http_parser_g.o test_g.o -o $@
@@ -61,11 +83,17 @@ test_fast: http_parser.o test.o http_parser.h
test.o: test.c http_parser.h Makefile test.o: test.c http_parser.h Makefile
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c test.c -o $@ $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c test.c -o $@
bench: http_parser.o bench.o
$(CC) $(CFLAGS_BENCH) $(LDFLAGS) http_parser.o bench.o -o $@
bench.o: bench.c http_parser.h Makefile
$(CC) $(CPPFLAGS_BENCH) $(CFLAGS_BENCH) -c bench.c -o $@
http_parser.o: http_parser.c http_parser.h Makefile http_parser.o: http_parser.c http_parser.h Makefile
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c http_parser.c $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c http_parser.c
test-run-timed: test_fast test-run-timed: test_fast
while(true) do time ./test_fast > /dev/null; done while(true) do time $(HELPER) ./test_fast$(BINEXT) > /dev/null; done
test-valgrind: test_g test-valgrind: test_g
valgrind ./test_g valgrind ./test_g
@@ -86,20 +114,36 @@ url_parser_g: http_parser_g.o contrib/url_parser.c
$(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o $@ $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o $@
parsertrace: http_parser.o contrib/parsertrace.c parsertrace: http_parser.o contrib/parsertrace.c
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o parsertrace $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o parsertrace$(BINEXT)
parsertrace_g: http_parser_g.o contrib/parsertrace.c parsertrace_g: http_parser_g.o contrib/parsertrace.c
$(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g$(BINEXT)
tags: http_parser.c http_parser.h test.c tags: http_parser.c http_parser.h test.c
ctags $^ ctags $^
install: library
$(INSTALL) -D http_parser.h $(INCLUDEDIR)/http_parser.h
$(INSTALL) -D $(SONAME) $(LIBDIR)/$(SONAME)
ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.$(SOEXT)
install-strip: library
$(INSTALL) -D http_parser.h $(INCLUDEDIR)/http_parser.h
$(INSTALL) -D -s $(SONAME) $(LIBDIR)/$(SONAME)
ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.$(SOEXT)
uninstall:
rm $(INCLUDEDIR)/http_parser.h
rm $(LIBDIR)/$(SONAME)
rm $(LIBDIR)/libhttp_parser.so
clean: clean:
rm -f *.o *.a tags test test_fast test_g \ rm -f *.o *.a tags test test_fast test_g \
http_parser.tar libhttp_parser.so.* \ http_parser.tar libhttp_parser.so.* \
url_parser url_parser_g parsertrace parsertrace_g url_parser url_parser_g parsertrace parsertrace_g \
*.exe *.exe.so
contrib/url_parser.c: http_parser.h contrib/url_parser.c: http_parser.h
contrib/parsertrace.c: http_parser.h contrib/parsertrace.c: http_parser.h
.PHONY: clean package test-run test-run-timed test-valgrind .PHONY: clean package test-run test-run-timed test-valgrind install install-strip uninstall

View File

@@ -1,7 +1,7 @@
HTTP Parser HTTP Parser
=========== ===========
[![Build Status](https://travis-ci.org/joyent/http-parser.png?branch=master)](https://travis-ci.org/joyent/http-parser) [![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser)
This is a parser for HTTP messages written in C. It parses both requests and This is a parser for HTTP messages written in C. It parses both requests and
responses. The parser is designed to be used in performance HTTP responses. The parser is designed to be used in performance HTTP
@@ -61,7 +61,7 @@ if (recved < 0) {
} }
/* Start up / continue the parser. /* Start up / continue the parser.
* Note we pass recved==0 to signal that EOF has been recieved. * Note we pass recved==0 to signal that EOF has been received.
*/ */
nparsed = http_parser_execute(parser, &settings, buf, recved); nparsed = http_parser_execute(parser, &settings, buf, recved);
@@ -75,7 +75,7 @@ if (parser->upgrade) {
HTTP needs to know where the end of the stream is. For example, sometimes HTTP needs to know where the end of the stream is. For example, sometimes
servers send responses without Content-Length and expect the client to servers send responses without Content-Length and expect the client to
consume input (for the body) until EOF. To tell http_parser about EOF, give consume input (for the body) until EOF. To tell http_parser about EOF, give
`0` as the forth parameter to `http_parser_execute()`. Callbacks and errors `0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors
can still be encountered during an EOF, so one must still be prepared can still be encountered during an EOF, so one must still be prepared
to receive them. to receive them.
@@ -94,7 +94,7 @@ The Special Problem of Upgrade
------------------------------ ------------------------------
HTTP supports upgrading the connection to a different protocol. An HTTP supports upgrading the connection to a different protocol. An
increasingly common example of this is the Web Socket protocol which sends increasingly common example of this is the WebSocket protocol which sends
a request like a request like
GET /demo HTTP/1.1 GET /demo HTTP/1.1
@@ -106,11 +106,11 @@ a request like
followed by non-HTTP data. followed by non-HTTP data.
(See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more (See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the
information the Web Socket protocol.) WebSocket protocol.)
To support this, the parser will treat this as a normal HTTP message without a To support this, the parser will treat this as a normal HTTP message without a
body. Issuing both on_headers_complete and on_message_complete callbacks. However body, issuing both on_headers_complete and on_message_complete callbacks. However
http_parser_execute() will stop parsing at the end of the headers and return. http_parser_execute() will stop parsing at the end of the headers and return.
The user is expected to check if `parser->upgrade` has been set to 1 after The user is expected to check if `parser->upgrade` has been set to 1 after
@@ -128,15 +128,78 @@ save certain data for later usage, you can do that from the callbacks.
There are two types of callbacks: There are two types of callbacks:
* notification `using http_cb = int (*) (http_parser*);` * notification `typedef int (*http_cb) (http_parser*);`
Callbacks: on_message_begin, on_headers_complete, on_message_complete. Callbacks: on_message_begin, on_headers_complete, on_message_complete.
* data `using http_data_cb = int (*) (http_parser*, const char *at, size_t length);` * data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
Callbacks: (requests only) on_uri, Callbacks: (requests only) on_url,
(common) on_header_field, on_header_value, on_body; (common) on_header_field, on_header_value, on_body;
Callbacks must return 0 on success. Returning a non-zero value indicates Callbacks must return 0 on success. Returning a non-zero value indicates
error to the parser, making it exit immediately. error to the parser, making it exit immediately.
For cases where it is necessary to pass local information to/from a callback,
the `http_parser` object's `data` field can be used.
An example of such a case is when using threads to handle a socket connection,
parse a request, and then give a response over that socket. By instantiation
of a thread-local struct containing relevant data (e.g. accepted socket,
allocated memory for callbacks to write into, etc), a parser's callbacks are
able to communicate data between the scope of the thread and the scope of the
callback in a threadsafe manner. This allows http-parser to be used in
multi-threaded contexts.
Example:
```
typedef struct {
socket_t sock;
void* buffer;
int buf_len;
} custom_data_t;
int my_url_callback(http_parser* parser, const char *at, size_t length) {
/* access to thread local custom_data_t struct.
Use this access save parsed data for later use into thread local
buffer, or communicate over socket
*/
parser->data;
...
return 0;
}
...
void http_parser_thread(socket_t sock) {
int nparsed = 0;
/* allocate memory for user data */
custom_data_t *my_data = malloc(sizeof(custom_data_t));
/* some information for use by callbacks.
* achieves thread -> callback information flow */
my_data->sock = sock;
/* instantiate a thread-local parser */
http_parser *parser = malloc(sizeof(http_parser));
http_parser_init(parser, HTTP_REQUEST); /* initialise parser */
/* this custom data reference is accessible through the reference to the
parser supplied to callback functions */
parser->data = my_data;
http_parser_settings settings; / * set up callbacks */
settings.on_url = my_url_callback;
/* execute parser */
nparsed = http_parser_execute(parser, &settings, buf, recved);
...
/* parsed information copied from callback.
can now perform action on data copied into thread-local memory from callbacks.
achieves callback -> thread information flow */
my_data->buffer;
...
}
```
In case you parse HTTP message in chunks (i.e. `read()` request line In case you parse HTTP message in chunks (i.e. `read()` request line
from socket, parse, read half headers, parse, etc) your data callbacks from socket, parse, read half headers, parse, etc) your data callbacks
may be called more than once. Http-parser guarantees that data pointer is only may be called more than once. Http-parser guarantees that data pointer is only
@@ -145,7 +208,7 @@ buffer to avoid copying memory around if this fits your application.
Reading headers may be a tricky task if you read/parse headers partially. Reading headers may be a tricky task if you read/parse headers partially.
Basically, you need to remember whether last header callback was field or value Basically, you need to remember whether last header callback was field or value
and apply following logic: and apply the following logic:
(on_header_field and on_header_value shortened to on_h_*) (on_header_field and on_header_value shortened to on_h_*)
------------------------ ------------ -------------------------------------------- ------------------------ ------------ --------------------------------------------

View File

@@ -0,0 +1,111 @@
/* Copyright Fedor Indutny. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "http_parser.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
static const char data[] =
"POST /joyent/http-parser HTTP/1.1\r\n"
"Host: github.com\r\n"
"DNT: 1\r\n"
"Accept-Encoding: gzip, deflate, sdch\r\n"
"Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4\r\n"
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/39.0.2171.65 Safari/537.36\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/webp,*/*;q=0.8\r\n"
"Referer: https://github.com/joyent/http-parser\r\n"
"Connection: keep-alive\r\n"
"Transfer-Encoding: chunked\r\n"
"Cache-Control: max-age=0\r\n\r\nb\r\nhello world\r\n0\r\n\r\n";
static const size_t data_len = sizeof(data) - 1;
static int on_info(http_parser* p) {
return 0;
}
static int on_data(http_parser* p, const char *at, size_t length) {
return 0;
}
static http_parser_settings settings = {
.on_message_begin = on_info,
.on_headers_complete = on_info,
.on_message_complete = on_info,
.on_header_field = on_data,
.on_header_value = on_data,
.on_url = on_data,
.on_status = on_data,
.on_body = on_data
};
int bench(int iter_count, int silent) {
struct http_parser parser;
int i;
int err;
struct timeval start;
struct timeval end;
float rps;
if (!silent) {
err = gettimeofday(&start, NULL);
assert(err == 0);
}
for (i = 0; i < iter_count; i++) {
size_t parsed;
http_parser_init(&parser, HTTP_REQUEST);
parsed = http_parser_execute(&parser, &settings, data, data_len);
assert(parsed == data_len);
}
if (!silent) {
err = gettimeofday(&end, NULL);
assert(err == 0);
fprintf(stdout, "Benchmark result:\n");
rps = (float) (end.tv_sec - start.tv_sec) +
(end.tv_usec - start.tv_usec) * 1e-6f;
fprintf(stdout, "Took %f seconds to run\n", rps);
rps = (float) iter_count / rps;
fprintf(stdout, "%f req/sec\n", rps);
fflush(stdout);
}
return 0;
}
int main(int argc, char** argv) {
if (argc == 2 && strcmp(argv[1], "infinite") == 0) {
for (;;)
bench(5000000, 1);
return 0;
} else {
return bench(5000000, 0);
}
}

View File

@@ -111,14 +111,14 @@ int main(int argc, char* argv[]) {
FILE* file = fopen(filename, "r"); FILE* file = fopen(filename, "r");
if (file == NULL) { if (file == NULL) {
perror("fopen"); perror("fopen");
return EXIT_FAILURE; goto fail;
} }
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
long file_length = ftell(file); long file_length = ftell(file);
if (file_length == -1) { if (file_length == -1) {
perror("ftell"); perror("ftell");
return EXIT_FAILURE; goto fail;
} }
fseek(file, 0, SEEK_SET); fseek(file, 0, SEEK_SET);
@@ -126,7 +126,7 @@ int main(int argc, char* argv[]) {
if (fread(data, 1, file_length, file) != (size_t)file_length) { if (fread(data, 1, file_length, file) != (size_t)file_length) {
fprintf(stderr, "couldn't read entire file\n"); fprintf(stderr, "couldn't read entire file\n");
free(data); free(data);
return EXIT_FAILURE; goto fail;
} }
http_parser_settings settings; http_parser_settings settings;
@@ -149,8 +149,12 @@ int main(int argc, char* argv[]) {
"Error: %s (%s)\n", "Error: %s (%s)\n",
http_errno_description(HTTP_PARSER_ERRNO(&parser)), http_errno_description(HTTP_PARSER_ERRNO(&parser)),
http_errno_name(HTTP_PARSER_ERRNO(&parser))); http_errno_name(HTTP_PARSER_ERRNO(&parser)));
return EXIT_FAILURE; goto fail;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
fail:
fclose(file);
return EXIT_FAILURE;
} }

View File

@@ -14,7 +14,7 @@ dump_url (const char *url, const struct http_parser_url *u)
continue; continue;
} }
printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n", printf("\tfield_data[%u]: off: %u, len: %u, part: %.*s\n",
i, i,
u->field_data[i].off, u->field_data[i].off,
u->field_data[i].len, u->field_data[i].len,
@@ -24,16 +24,19 @@ dump_url (const char *url, const struct http_parser_url *u)
} }
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
struct http_parser_url u;
int len, connect, result;
if (argc != 3) { if (argc != 3) {
printf("Syntax : %s connect|get url\n", argv[0]); printf("Syntax : %s connect|get url\n", argv[0]);
return 1; return 1;
} }
struct http_parser_url u; len = strlen(argv[2]);
int len = strlen(argv[2]); connect = strcmp("connect", argv[1]) == 0 ? 1 : 0;
int connect = strcmp("connect", argv[1]) == 0 ? 1 : 0;
printf("Parsing %s, connect %d\n", argv[2], connect); printf("Parsing %s, connect %d\n", argv[2], connect);
int result = http_parser_parse_url(argv[2], len, connect, &u); http_parser_url_init(&u);
result = http_parser_parse_url(argv[2], len, connect, &u);
if (result != 0) { if (result != 0) {
printf("Parse error : %d\n", result); printf("Parse error : %d\n", result);
return result; return result;
@@ -41,4 +44,4 @@ int main(int argc, char ** argv) {
printf("Parse ok, result : \n"); printf("Parse ok, result : \n");
dump_url(argv[2], &u); dump_url(argv[2], &u);
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -27,11 +27,12 @@ extern "C" {
/* Also update SONAME in the Makefile whenever you change these. */ /* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2 #define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 2 #define HTTP_PARSER_VERSION_MINOR 6
#define HTTP_PARSER_VERSION_PATCH 1 #define HTTP_PARSER_VERSION_PATCH 1
#include <sys/types.h> #include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) #if defined(_WIN32) && !defined(__MINGW32__) && \
(!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
#include <BaseTsd.h> #include <BaseTsd.h>
#include <stddef.h> #include <stddef.h>
typedef __int8 int8_t; typedef __int8 int8_t;
@@ -53,9 +54,16 @@ typedef unsigned __int64 uint64_t;
# define HTTP_PARSER_STRICT 1 # define HTTP_PARSER_STRICT 1
#endif #endif
/* Maximium header size allowed */ /* Maximium header size allowed. If the macro is not defined
#define HTTP_MAX_HEADER_SIZE (80*1024) * before including this header then the default is used. To
* change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
#ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser; typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings; typedef struct http_parser_settings http_parser_settings;
@@ -70,7 +78,7 @@ typedef struct http_parser_settings http_parser_settings;
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
* chunked' headers that indicate the presence of a body. * chunked' headers that indicate the presence of a body.
* *
* http_data_cb does not return data chunks. It will be call arbitrarally * http_data_cb does not return data chunks. It will be called arbitrarily
* many times for each string. E.G. you might get 10 callbacks for "on_url" * many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data. * each providing just a few characters more data.
*/ */
@@ -89,7 +97,7 @@ typedef int (*http_cb) (http_parser*);
XX(5, CONNECT, CONNECT) \ XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \ XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \ XX(7, TRACE, TRACE) \
/* webdav */ \ /* WebDAV */ \
XX(8, COPY, COPY) \ XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \ XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \ XX(10, MKCOL, MKCOL) \
@@ -98,19 +106,28 @@ typedef int (*http_cb) (http_parser*);
XX(13, PROPPATCH, PROPPATCH) \ XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \ XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \ XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
/* subversion */ \ /* subversion */ \
XX(16, REPORT, REPORT) \ XX(20, REPORT, REPORT) \
XX(17, MKACTIVITY, MKACTIVITY) \ XX(21, MKACTIVITY, MKACTIVITY) \
XX(18, CHECKOUT, CHECKOUT) \ XX(22, CHECKOUT, CHECKOUT) \
XX(19, MERGE, MERGE) \ XX(23, MERGE, MERGE) \
/* upnp */ \ /* upnp */ \
XX(20, MSEARCH, M-SEARCH) \ XX(24, MSEARCH, M-SEARCH) \
XX(21, NOTIFY, NOTIFY) \ XX(25, NOTIFY, NOTIFY) \
XX(22, SUBSCRIBE, SUBSCRIBE) \ XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \ /* RFC-5789 */ \
XX(24, PATCH, PATCH) \ XX(28, PATCH, PATCH) \
XX(25, PURGE, PURGE) \ XX(29, PURGE, PURGE) \
/* CalDAV */ \
XX(30, MKCALENDAR, MKCALENDAR) \
/* RFC-2068, section 19.6.1.2 */ \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
enum http_method enum http_method
{ {
@@ -128,9 +145,11 @@ enum flags
{ F_CHUNKED = 1 << 0 { F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1 , F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2 , F_CONNECTION_CLOSE = 1 << 2
, F_TRAILING = 1 << 3 , F_CONNECTION_UPGRADE = 1 << 3
, F_UPGRADE = 1 << 4 , F_TRAILING = 1 << 4
, F_SKIPBODY = 1 << 5 , F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
, F_CONTENTLENGTH = 1 << 7
}; };
@@ -151,6 +170,8 @@ enum flags
XX(CB_body, "the on_body callback failed") \ XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \ XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \ XX(CB_status, "the on_status callback failed") \
XX(CB_chunk_header, "the on_chunk_header callback failed") \
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
\ \
/* Parsing-related errors */ \ /* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
@@ -171,6 +192,8 @@ enum flags
XX(INVALID_HEADER_TOKEN, "invalid character in header") \ XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, \ XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \ "invalid character in content-length header") \
XX(UNEXPECTED_CONTENT_LENGTH, \
"unexpected content-length header") \
XX(INVALID_CHUNK_SIZE, \ XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \ "invalid character in chunk size header") \
XX(INVALID_CONSTANT, "invalid constant string") \ XX(INVALID_CONSTANT, "invalid constant string") \
@@ -195,10 +218,11 @@ enum http_errno {
struct http_parser { struct http_parser {
/** PRIVATE **/ /** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */ unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */ unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 8; /* enum state from http_parser.c */ unsigned int state : 7; /* enum state from http_parser.c */
unsigned int header_state : 8; /* enum header_state from http_parser.c */ unsigned int header_state : 7; /* enum header_state from http_parser.c */
unsigned int index : 8; /* index into current matcher */ unsigned int index : 7; /* index into current matcher */
unsigned int lenient_http_headers : 1;
uint32_t nread; /* # bytes read in various scenarios */ uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
@@ -231,6 +255,11 @@ struct http_parser_settings {
http_cb on_headers_complete; http_cb on_headers_complete;
http_data_cb on_body; http_data_cb on_body;
http_cb on_message_complete; http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
}; };
@@ -272,13 +301,20 @@ struct http_parser_url {
* unsigned major = (version >> 16) & 255; * unsigned major = (version >> 16) & 255;
* unsigned minor = (version >> 8) & 255; * unsigned minor = (version >> 8) & 255;
* unsigned patch = version & 255; * unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, version); * printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/ */
unsigned long http_parser_version(void); unsigned long http_parser_version(void);
void http_parser_init(http_parser *parser, enum http_parser_type type); void http_parser_init(http_parser *parser, enum http_parser_type type);
/* Initialize http_parser_settings members to 0
*/
void http_parser_settings_init(http_parser_settings *settings);
/* Executes the parser. Returns number of parsed bytes. Sets
* `parser->http_errno` on error. */
size_t http_parser_execute(http_parser *parser, size_t http_parser_execute(http_parser *parser,
const http_parser_settings *settings, const http_parser_settings *settings,
const char *data, const char *data,
@@ -302,6 +338,9 @@ const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */ /* Return a string description of the given error */
const char *http_errno_description(enum http_errno err); const char *http_errno_description(enum http_errno err);
/* Initialize all http_parser_url members to 0 */
void http_parser_url_init(struct http_parser_url *u);
/* Parse a URL; return nonzero on failure */ /* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen, int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect, int is_connect,

View File

@@ -39,6 +39,7 @@
#define MAX_HEADERS 13 #define MAX_HEADERS 13
#define MAX_ELEMENT_SIZE 2048 #define MAX_ELEMENT_SIZE 2048
#define MAX_CHUNKS 16
#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -65,6 +66,10 @@ struct message {
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE]; char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
int should_keep_alive; int should_keep_alive;
int num_chunks;
int num_chunks_complete;
int chunk_lengths[MAX_CHUNKS];
const char *upgrade; // upgraded body const char *upgrade; // upgraded body
unsigned short http_major; unsigned short http_major;
@@ -301,6 +306,8 @@ const struct message requests[] =
{ { "Transfer-Encoding" , "chunked" } { { "Transfer-Encoding" , "chunked" }
} }
,.body= "all your base are belong to us" ,.body= "all your base are belong to us"
,.num_chunks_complete= 2
,.chunk_lengths= { 0x1e }
} }
#define TWO_CHUNKS_MULT_ZERO_END 9 #define TWO_CHUNKS_MULT_ZERO_END 9
@@ -327,6 +334,8 @@ const struct message requests[] =
{ { "Transfer-Encoding", "chunked" } { { "Transfer-Encoding", "chunked" }
} }
,.body= "hello world" ,.body= "hello world"
,.num_chunks_complete= 3
,.chunk_lengths= { 5, 6 }
} }
#define CHUNKED_W_TRAILING_HEADERS 10 #define CHUNKED_W_TRAILING_HEADERS 10
@@ -357,6 +366,8 @@ const struct message requests[] =
, { "Content-Type", "text/plain" } , { "Content-Type", "text/plain" }
} }
,.body= "hello world" ,.body= "hello world"
,.num_chunks_complete= 3
,.chunk_lengths= { 5, 6 }
} }
#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11 #define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
@@ -383,6 +394,8 @@ const struct message requests[] =
{ { "Transfer-Encoding", "chunked" } { { "Transfer-Encoding", "chunked" }
} }
,.body= "hello world" ,.body= "hello world"
,.num_chunks_complete= 3
,.chunk_lengths= { 5, 6 }
} }
#define WITH_QUOTES 12 #define WITH_QUOTES 12
@@ -608,8 +621,14 @@ const struct message requests[] =
" mno \r\n" " mno \r\n"
"\t \tqrs\r\n" "\t \tqrs\r\n"
"Line2: \t line2\t\r\n" "Line2: \t line2\t\r\n"
"Line3:\r\n"
" line3\r\n"
"Line4: \r\n"
" \r\n"
"Connection:\r\n"
" close\r\n"
"\r\n" "\r\n"
,.should_keep_alive= TRUE ,.should_keep_alive= FALSE
,.message_complete_on_eof= FALSE ,.message_complete_on_eof= FALSE
,.http_major= 1 ,.http_major= 1
,.http_minor= 1 ,.http_minor= 1
@@ -618,9 +637,12 @@ const struct message requests[] =
,.fragment= "" ,.fragment= ""
,.request_path= "/" ,.request_path= "/"
,.request_url= "/" ,.request_url= "/"
,.num_headers= 2 ,.num_headers= 5
,.headers= { { "Line1", "abcdefghijklmno qrs" } ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
, { "Line2", "line2\t" } , { "Line2", "line2\t" }
, { "Line3", "line3" }
, { "Line4", "" }
, { "Connection", "close" },
} }
,.body= "" ,.body= ""
} }
@@ -904,6 +926,232 @@ const struct message requests[] =
,.body= "" ,.body= ""
} }
#define LINE_FOLDING_IN_HEADER_WITH_LF 34
, {.name= "line folding in header value"
,.type= HTTP_REQUEST
,.raw= "GET / HTTP/1.1\n"
"Line1: abc\n"
"\tdef\n"
" ghi\n"
"\t\tjkl\n"
" mno \n"
"\t \tqrs\n"
"Line2: \t line2\t\n"
"Line3:\n"
" line3\n"
"Line4: \n"
" \n"
"Connection:\n"
" close\n"
"\n"
,.should_keep_alive= FALSE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/"
,.request_url= "/"
,.num_headers= 5
,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
, { "Line2", "line2\t" }
, { "Line3", "line3" }
, { "Line4", "" }
, { "Connection", "close" },
}
,.body= ""
}
#define CONNECTION_MULTI 35
, {.name = "multiple connection header values with folding"
,.type= HTTP_REQUEST
,.raw= "GET /demo HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: Something,\r\n"
" Upgrade, ,Keep-Alive\r\n"
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
"Sec-WebSocket-Protocol: sample\r\n"
"Upgrade: WebSocket\r\n"
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
"Origin: http://example.com\r\n"
"\r\n"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 7
,.upgrade="Hot diggity dogg"
,.headers= { { "Host", "example.com" }
, { "Connection", "Something, Upgrade, ,Keep-Alive" }
, { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
, { "Sec-WebSocket-Protocol", "sample" }
, { "Upgrade", "WebSocket" }
, { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
, { "Origin", "http://example.com" }
}
,.body= ""
}
#define CONNECTION_MULTI_LWS 36
, {.name = "multiple connection header values with folding and lws"
,.type= HTTP_REQUEST
,.raw= "GET /demo HTTP/1.1\r\n"
"Connection: keep-alive, upgrade\r\n"
"Upgrade: WebSocket\r\n"
"\r\n"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 2
,.upgrade="Hot diggity dogg"
,.headers= { { "Connection", "keep-alive, upgrade" }
, { "Upgrade", "WebSocket" }
}
,.body= ""
}
#define CONNECTION_MULTI_LWS_CRLF 37
, {.name = "multiple connection header values with folding and lws"
,.type= HTTP_REQUEST
,.raw= "GET /demo HTTP/1.1\r\n"
"Connection: keep-alive, \r\n upgrade\r\n"
"Upgrade: WebSocket\r\n"
"\r\n"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 2
,.upgrade="Hot diggity dogg"
,.headers= { { "Connection", "keep-alive, upgrade" }
, { "Upgrade", "WebSocket" }
}
,.body= ""
}
#define UPGRADE_POST_REQUEST 38
, {.name = "upgrade post request"
,.type= HTTP_REQUEST
,.raw= "POST /demo HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: Upgrade\r\n"
"Upgrade: HTTP/2.0\r\n"
"Content-Length: 15\r\n"
"\r\n"
"sweet post body"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_POST
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 4
,.upgrade="Hot diggity dogg"
,.headers= { { "Host", "example.com" }
, { "Connection", "Upgrade" }
, { "Upgrade", "HTTP/2.0" }
, { "Content-Length", "15" }
}
,.body= "sweet post body"
}
#define CONNECT_WITH_BODY_REQUEST 39
, {.name = "connect with body request"
,.type= HTTP_REQUEST
,.raw= "CONNECT foo.bar.com:443 HTTP/1.0\r\n"
"User-agent: Mozilla/1.1N\r\n"
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
"Content-Length: 10\r\n"
"\r\n"
"blarfcicle"
,.should_keep_alive= FALSE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 0
,.method= HTTP_CONNECT
,.request_url= "foo.bar.com:443"
,.num_headers= 3
,.upgrade="blarfcicle"
,.headers= { { "User-agent", "Mozilla/1.1N" }
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
, { "Content-Length", "10" }
}
,.body= ""
}
/* Examples from the Internet draft for LINK/UNLINK methods:
* https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5
*/
#define LINK_REQUEST 40
, {.name = "link request"
,.type= HTTP_REQUEST
,.raw= "LINK /images/my_dog.jpg HTTP/1.1\r\n"
"Host: example.com\r\n"
"Link: <http://example.com/profiles/joe>; rel=\"tag\"\r\n"
"Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_LINK
,.request_path= "/images/my_dog.jpg"
,.request_url= "/images/my_dog.jpg"
,.query_string= ""
,.fragment= ""
,.num_headers= 3
,.headers= { { "Host", "example.com" }
, { "Link", "<http://example.com/profiles/joe>; rel=\"tag\"" }
, { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
}
,.body= ""
}
#define UNLINK_REQUEST 41
, {.name = "link request"
,.type= HTTP_REQUEST
,.raw= "UNLINK /images/my_dog.jpg HTTP/1.1\r\n"
"Host: example.com\r\n"
"Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_UNLINK
,.request_path= "/images/my_dog.jpg"
,.request_url= "/images/my_dog.jpg"
,.query_string= ""
,.fragment= ""
,.num_headers= 2
,.headers= { { "Host", "example.com" }
, { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
}
,.body= ""
}
, {.name= NULL } /* sentinel */ , {.name= NULL } /* sentinel */
}; };
@@ -1064,7 +1312,8 @@ const struct message responses[] =
,.body = ,.body =
"This is the data in the first chunk\r\n" "This is the data in the first chunk\r\n"
"and this is the second one\r\n" "and this is the second one\r\n"
,.num_chunks_complete= 3
,.chunk_lengths= { 0x25, 0x1c }
} }
#define NO_CARRIAGE_RET 5 #define NO_CARRIAGE_RET 5
@@ -1218,6 +1467,8 @@ const struct message responses[] =
, { "Connection", "close" } , { "Connection", "close" }
} }
,.body= "" ,.body= ""
,.num_chunks_complete= 1
,.chunk_lengths= {}
} }
#define NON_ASCII_IN_STATUS_LINE 10 #define NON_ASCII_IN_STATUS_LINE 10
@@ -1400,6 +1651,7 @@ const struct message responses[] =
} }
,.body_size= 0 ,.body_size= 0
,.body= "" ,.body= ""
,.num_chunks_complete= 1
} }
#if !HTTP_PARSER_STRICT #if !HTTP_PARSER_STRICT
@@ -1473,6 +1725,8 @@ const struct message responses[] =
, { "Transfer-Encoding", "chunked" } , { "Transfer-Encoding", "chunked" }
} }
,.body= "\n" ,.body= "\n"
,.num_chunks_complete= 2
,.chunk_lengths= { 1 }
} }
#define EMPTY_REASON_PHRASE_AFTER_SPACE 20 #define EMPTY_REASON_PHRASE_AFTER_SPACE 20
@@ -1708,6 +1962,35 @@ response_status_cb (http_parser *p, const char *buf, size_t len)
return 0; return 0;
} }
int
chunk_header_cb (http_parser *p)
{
assert(p == parser);
int chunk_idx = messages[num_messages].num_chunks;
messages[num_messages].num_chunks++;
if (chunk_idx < MAX_CHUNKS) {
messages[num_messages].chunk_lengths[chunk_idx] = p->content_length;
}
return 0;
}
int
chunk_complete_cb (http_parser *p)
{
assert(p == parser);
/* Here we want to verify that each chunk_header_cb is matched by a
* chunk_complete_cb, so not only should the total number of calls to
* both callbacks be the same, but they also should be interleaved
* properly */
assert(messages[num_messages].num_chunks ==
messages[num_messages].num_chunks_complete + 1);
messages[num_messages].num_chunks_complete++;
return 0;
}
/* These dontcall_* callbacks exist so that we can verify that when we're /* These dontcall_* callbacks exist so that we can verify that when we're
* paused, no additional callbacks are invoked */ * paused, no additional callbacks are invoked */
int int
@@ -1776,6 +2059,23 @@ dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
abort(); abort();
} }
int
dontcall_chunk_header_cb (http_parser *p)
{
if (p) { } // gcc
fprintf(stderr, "\n\n*** on_chunk_header() called on paused parser ***\n\n");
exit(1);
}
int
dontcall_chunk_complete_cb (http_parser *p)
{
if (p) { } // gcc
fprintf(stderr, "\n\n*** on_chunk_complete() "
"called on paused parser ***\n\n");
exit(1);
}
static http_parser_settings settings_dontcall = static http_parser_settings settings_dontcall =
{.on_message_begin = dontcall_message_begin_cb {.on_message_begin = dontcall_message_begin_cb
,.on_header_field = dontcall_header_field_cb ,.on_header_field = dontcall_header_field_cb
@@ -1785,6 +2085,8 @@ static http_parser_settings settings_dontcall =
,.on_body = dontcall_body_cb ,.on_body = dontcall_body_cb
,.on_headers_complete = dontcall_headers_complete_cb ,.on_headers_complete = dontcall_headers_complete_cb
,.on_message_complete = dontcall_message_complete_cb ,.on_message_complete = dontcall_message_complete_cb
,.on_chunk_header = dontcall_chunk_header_cb
,.on_chunk_complete = dontcall_chunk_complete_cb
}; };
/* These pause_* callbacks always pause the parser and just invoke the regular /* These pause_* callbacks always pause the parser and just invoke the regular
@@ -1855,6 +2157,22 @@ pause_response_status_cb (http_parser *p, const char *buf, size_t len)
return response_status_cb(p, buf, len); return response_status_cb(p, buf, len);
} }
int
pause_chunk_header_cb (http_parser *p)
{
http_parser_pause(p, 1);
*current_pause_parser = settings_dontcall;
return chunk_header_cb(p);
}
int
pause_chunk_complete_cb (http_parser *p)
{
http_parser_pause(p, 1);
*current_pause_parser = settings_dontcall;
return chunk_complete_cb(p);
}
static http_parser_settings settings_pause = static http_parser_settings settings_pause =
{.on_message_begin = pause_message_begin_cb {.on_message_begin = pause_message_begin_cb
,.on_header_field = pause_header_field_cb ,.on_header_field = pause_header_field_cb
@@ -1864,6 +2182,8 @@ static http_parser_settings settings_pause =
,.on_body = pause_body_cb ,.on_body = pause_body_cb
,.on_headers_complete = pause_headers_complete_cb ,.on_headers_complete = pause_headers_complete_cb
,.on_message_complete = pause_message_complete_cb ,.on_message_complete = pause_message_complete_cb
,.on_chunk_header = pause_chunk_header_cb
,.on_chunk_complete = pause_chunk_complete_cb
}; };
static http_parser_settings settings = static http_parser_settings settings =
@@ -1875,6 +2195,8 @@ static http_parser_settings settings =
,.on_body = body_cb ,.on_body = body_cb
,.on_headers_complete = headers_complete_cb ,.on_headers_complete = headers_complete_cb
,.on_message_complete = message_complete_cb ,.on_message_complete = message_complete_cb
,.on_chunk_header = chunk_header_cb
,.on_chunk_complete = chunk_complete_cb
}; };
static http_parser_settings settings_count_body = static http_parser_settings settings_count_body =
@@ -1886,6 +2208,8 @@ static http_parser_settings settings_count_body =
,.on_body = count_body_cb ,.on_body = count_body_cb
,.on_headers_complete = headers_complete_cb ,.on_headers_complete = headers_complete_cb
,.on_message_complete = message_complete_cb ,.on_message_complete = message_complete_cb
,.on_chunk_header = chunk_header_cb
,.on_chunk_complete = chunk_complete_cb
}; };
static http_parser_settings settings_null = static http_parser_settings settings_null =
@@ -1897,6 +2221,8 @@ static http_parser_settings settings_null =
,.on_body = 0 ,.on_body = 0
,.on_headers_complete = 0 ,.on_headers_complete = 0
,.on_message_complete = 0 ,.on_message_complete = 0
,.on_chunk_header = 0
,.on_chunk_complete = 0
}; };
void void
@@ -2065,6 +2391,12 @@ message_eq (int index, const struct message *expected)
MESSAGE_CHECK_STR_EQ(expected, m, body); MESSAGE_CHECK_STR_EQ(expected, m, body);
} }
assert(m->num_chunks == m->num_chunks_complete);
MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete);
for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) {
MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]);
}
MESSAGE_CHECK_NUM_EQ(expected, m, num_headers); MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
int r; int r;
@@ -2112,7 +2444,7 @@ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
va_list ap; va_list ap;
size_t i; size_t i;
size_t off = 0; size_t off = 0;
va_start(ap, nmsgs); va_start(ap, nmsgs);
for (i = 0; i < nmsgs; i++) { for (i = 0; i < nmsgs; i++) {
@@ -2161,7 +2493,6 @@ print_error (const char *raw, size_t error_location)
break; break;
case '\n': case '\n':
char_len = 2;
fprintf(stderr, "\\n\n"); fprintf(stderr, "\\n\n");
if (this_line) goto print; if (this_line) goto print;
@@ -2639,6 +2970,59 @@ const struct url_test url_tests[] =
,.rv=1 /* s_dead */ ,.rv=1 /* s_dead */
} }
, {.name="ipv6 address with Zone ID"
,.url="http://[fe80::a%25eth0]/"
,.is_connect=0
,.u=
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
,.port=0
,.field_data=
{{ 0, 4 } /* UF_SCHEMA */
,{ 8, 14 } /* UF_HOST */
,{ 0, 0 } /* UF_PORT */
,{ 23, 1 } /* UF_PATH */
,{ 0, 0 } /* UF_QUERY */
,{ 0, 0 } /* UF_FRAGMENT */
,{ 0, 0 } /* UF_USERINFO */
}
}
,.rv=0
}
, {.name="ipv6 address with Zone ID, but '%' is not percent-encoded"
,.url="http://[fe80::a%eth0]/"
,.is_connect=0
,.u=
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
,.port=0
,.field_data=
{{ 0, 4 } /* UF_SCHEMA */
,{ 8, 12 } /* UF_HOST */
,{ 0, 0 } /* UF_PORT */
,{ 21, 1 } /* UF_PATH */
,{ 0, 0 } /* UF_QUERY */
,{ 0, 0 } /* UF_FRAGMENT */
,{ 0, 0 } /* UF_USERINFO */
}
}
,.rv=0
}
, {.name="ipv6 address ending with '%'"
,.url="http://[fe80::a%]/"
,.rv=1 /* s_dead */
}
, {.name="ipv6 address with Zone ID including bad character"
,.url="http://[fe80::a%$HOME]/"
,.rv=1 /* s_dead */
}
, {.name="just ipv6 Zone ID"
,.url="http://[%eth0]/"
,.rv=1 /* s_dead */
}
#if HTTP_PARSER_STRICT #if HTTP_PARSER_STRICT
, {.name="tab in URL" , {.name="tab in URL"
@@ -2779,7 +3163,7 @@ test_message (const struct message *message)
if (msg1len) { if (msg1len) {
read = parse(msg1, msg1len); read = parse(msg1, msg1len);
if (message->upgrade && parser->upgrade) { if (message->upgrade && parser->upgrade && num_messages > 0) {
messages[num_messages - 1].upgrade = msg1 + read; messages[num_messages - 1].upgrade = msg1 + read;
goto test; goto test;
} }
@@ -2864,15 +3248,11 @@ test_simple (const char *buf, enum http_errno err_expected)
{ {
parser_init(HTTP_REQUEST); parser_init(HTTP_REQUEST);
size_t parsed;
int pass;
enum http_errno err; enum http_errno err;
parsed = parse(buf, strlen(buf)); parse(buf, strlen(buf));
pass = (parsed == strlen(buf));
err = HTTP_PARSER_ERRNO(parser); err = HTTP_PARSER_ERRNO(parser);
parsed = parse(NULL, 0); parse(NULL, 0);
pass &= (parsed == 0);
parser_free(); parser_free();
@@ -2890,6 +3270,155 @@ test_simple (const char *buf, enum http_errno err_expected)
} }
} }
void
test_invalid_header_content (int req, const char* str)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = str;
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
return;
}
fprintf(stderr,
"\n*** Error expected but none in invalid header content test ***\n");
abort();
}
void
test_invalid_header_field_content_error (int req)
{
test_invalid_header_content(req, "Foo: F\01ailure");
test_invalid_header_content(req, "Foo: B\02ar");
}
void
test_invalid_header_field (int req, const char* str)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = str;
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
return;
}
fprintf(stderr,
"\n*** Error expected but none in invalid header token test ***\n");
abort();
}
void
test_invalid_header_field_token_error (int req)
{
test_invalid_header_field(req, "Fo@: Failure");
test_invalid_header_field(req, "Foo\01\test: Bar");
}
void
test_double_content_length_error (int req)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n";
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
return;
}
fprintf(stderr,
"\n*** Error expected but none in double content-length test ***\n");
abort();
}
void
test_chunked_content_length_error (int req)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
return;
}
fprintf(stderr,
"\n*** Error expected but none in chunked content-length test ***\n");
abort();
}
void
test_header_cr_no_lf_error (int req)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = "Foo: 1\rBar: 1\r\n\r\n";
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_LF_EXPECTED);
return;
}
fprintf(stderr,
"\n*** Error expected but none in header whitespace test ***\n");
abort();
}
void void
test_header_overflow_error (int req) test_header_overflow_error (int req)
{ {
@@ -2918,6 +3447,22 @@ test_header_overflow_error (int req)
abort(); abort();
} }
void
test_header_nread_value ()
{
http_parser parser;
http_parser_init(&parser, HTTP_REQUEST);
size_t parsed;
const char *buf;
buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
assert(parser.nread == strlen(buf));
}
static void static void
test_content_length_overflow (const char *buf, size_t buflen, int expect_ok) test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
{ {
@@ -3284,6 +3829,9 @@ main (void)
test_parse_url(); test_parse_url();
test_method_str(); test_method_str();
//// NREAD
test_header_nread_value();
//// OVERFLOW CONDITIONS //// OVERFLOW CONDITIONS
test_header_overflow_error(HTTP_REQUEST); test_header_overflow_error(HTTP_REQUEST);
@@ -3297,6 +3845,18 @@ main (void)
test_header_content_length_overflow_error(); test_header_content_length_overflow_error();
test_chunk_content_length_overflow_error(); test_chunk_content_length_overflow_error();
//// HEADER FIELD CONDITIONS
test_double_content_length_error(HTTP_REQUEST);
test_chunked_content_length_error(HTTP_REQUEST);
test_header_cr_no_lf_error(HTTP_REQUEST);
test_invalid_header_field_token_error(HTTP_REQUEST);
test_invalid_header_field_content_error(HTTP_REQUEST);
test_double_content_length_error(HTTP_RESPONSE);
test_chunked_content_length_error(HTTP_RESPONSE);
test_header_cr_no_lf_error(HTTP_RESPONSE);
test_invalid_header_field_token_error(HTTP_RESPONSE);
test_invalid_header_field_content_error(HTTP_RESPONSE);
//// RESPONSES //// RESPONSES
for (i = 0; i < response_count; i++) { for (i = 0; i < response_count; i++) {
@@ -3343,7 +3903,11 @@ main (void)
, { "Content-Type", "text/plain" } , { "Content-Type", "text/plain" }
} }
,.body_size= 31337*1024 ,.body_size= 31337*1024
,.num_chunks_complete= 31338
}; };
for (i = 0; i < MAX_CHUNKS; i++) {
large_chunked.chunk_lengths[i] = 1024;
}
test_message_count_body(&large_chunked); test_message_count_body(&large_chunked);
free(msg); free(msg);
} }
@@ -3392,7 +3956,12 @@ main (void)
"MOVE", "MOVE",
"PROPFIND", "PROPFIND",
"PROPPATCH", "PROPPATCH",
"SEARCH",
"UNLOCK", "UNLOCK",
"BIND",
"REBIND",
"UNBIND",
"ACL",
"REPORT", "REPORT",
"MKACTIVITY", "MKACTIVITY",
"CHECKOUT", "CHECKOUT",
@@ -3402,6 +3971,10 @@ main (void)
"SUBSCRIBE", "SUBSCRIBE",
"UNSUBSCRIBE", "UNSUBSCRIBE",
"PATCH", "PATCH",
"PURGE",
"MKCALENDAR",
"LINK",
"UNLINK",
0 }; 0 };
const char **this_method; const char **this_method;
for (this_method = all_methods; *this_method; this_method++) { for (this_method = all_methods; *this_method; this_method++) {
@@ -3430,6 +4003,13 @@ main (void)
test_simple(buf, HPE_INVALID_METHOD); test_simple(buf, HPE_INVALID_METHOD);
} }
// illegal header field name line folding
test_simple("GET / HTTP/1.1\r\n"
"name\r\n"
" : value\r\n"
"\r\n",
HPE_INVALID_HEADER_TOKEN);
const char *dumbfuck2 = const char *dumbfuck2 =
"GET / HTTP/1.1\r\n" "GET / HTTP/1.1\r\n"
"X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n" "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n"
@@ -3467,6 +4047,22 @@ main (void)
"\r\n"; "\r\n";
test_simple(dumbfuck2, HPE_OK); test_simple(dumbfuck2, HPE_OK);
const char *corrupted_connection =
"GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Connection\r\033\065\325eep-Alive\r\n"
"Accept-Encoding: gzip\r\n"
"\r\n";
test_simple(corrupted_connection, HPE_INVALID_HEADER_TOKEN);
const char *corrupted_header_name =
"GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"X-Some-Header\r\033\065\325eep-Alive\r\n"
"Accept-Encoding: gzip\r\n"
"\r\n";
test_simple(corrupted_header_name, HPE_INVALID_HEADER_TOKEN);
#if 0 #if 0
// NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
// until EOF. // until EOF.

View File

@@ -83,6 +83,10 @@ convert_http_method (joyent::http_method m)
case HTTP_PROPPATCH: return http::method_t::http_proppatch; case HTTP_PROPPATCH: return http::method_t::http_proppatch;
case HTTP_SEARCH: return http::method_t::http_search; case HTTP_SEARCH: return http::method_t::http_search;
case HTTP_UNLOCK: return http::method_t::http_unlock; case HTTP_UNLOCK: return http::method_t::http_unlock;
case HTTP_BIND: return http::method_t::http_bind;
case HTTP_REBIND: return http::method_t::http_rebind;
case HTTP_UNBIND: return http::method_t::http_unbind;
case HTTP_ACL: return http::method_t::http_acl;
// subversion // subversion
case HTTP_REPORT: return http::method_t::http_report; case HTTP_REPORT: return http::method_t::http_report;
@@ -99,6 +103,13 @@ convert_http_method (joyent::http_method m)
// RFC-5789 // RFC-5789
case HTTP_PATCH: return http::method_t::http_patch; case HTTP_PATCH: return http::method_t::http_patch;
case HTTP_PURGE: return http::method_t::http_purge; case HTTP_PURGE: return http::method_t::http_purge;
// CalDav
case HTTP_MKCALENDAR: return http::method_t::http_mkcalendar;
// RFC-2068, section 19.6.1.2
case HTTP_LINK: return http::method_t::http_link;
case HTTP_UNLINK: return http::method_t::http_unlink;
}; };
return http::method_t::http_get; return http::method_t::http_get;

View File

@@ -1,292 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/http/raw_parser.h>
#include <beast/http/impl/joyent_parser.h>
#include <utility>
namespace beast {
namespace http {
raw_parser::raw_parser (callback& cb)
: m_cb (cb)
{
static_assert (sizeof(joyent::http_parser) == sizeof(state_t),
"state_t size must match http_parser size");
static_assert (sizeof(joyent::http_parser_settings) == sizeof(hooks_t),
"hooks_t size must match http_parser_settings size");
auto s (reinterpret_cast <joyent::http_parser*> (&m_state));
s->data = this;
auto h (reinterpret_cast <joyent::http_parser_settings*> (&m_hooks));
h->on_message_begin = &raw_parser::on_message_start;
h->on_url = &raw_parser::on_url;
h->on_status = &raw_parser::on_status;
h->on_header_field = &raw_parser::on_header_field;
h->on_header_value = &raw_parser::on_header_value;
h->on_headers_complete = &raw_parser::on_headers_done;
h->on_body = &raw_parser::on_body;
h->on_message_complete = &raw_parser::on_message_complete;
}
raw_parser::~raw_parser()
{
}
void
raw_parser::reset (message_type type)
{
auto s (reinterpret_cast <joyent::http_parser*> (&m_state));
http_parser_init (s, (type == request)
? joyent::HTTP_REQUEST : joyent::HTTP_RESPONSE);
}
auto
raw_parser::process_data (void const* buf, std::size_t bytes) ->
std::pair <error_code, std::size_t>
{
auto s (reinterpret_cast <joyent::http_parser*> (&m_state));
auto h (reinterpret_cast <joyent::http_parser_settings const*> (&m_hooks));
std::size_t const bytes_used (joyent::http_parser_execute (s, h,
static_cast <const char*> (buf), bytes));
return std::make_pair (m_ec, bytes_used);;
}
auto
raw_parser::process_eof () ->
error_code
{
auto s (reinterpret_cast <joyent::http_parser*> (&m_state));
auto h (reinterpret_cast <joyent::http_parser_settings const*> (&m_hooks));
joyent::http_parser_execute (s, h, nullptr, 0);
return m_ec;
}
//------------------------------------------------------------------------------
int
raw_parser::do_message_start ()
{
auto const p (reinterpret_cast <joyent::http_parser const*> (&m_state));
if (p->type == joyent::HTTP_REQUEST)
m_ec = m_cb.get().on_request ();
else if (p->type == joyent::HTTP_RESPONSE)
m_ec = m_cb.get().on_response ();
return m_ec ? 1 : 0;
}
int
raw_parser::do_url (char const* in, std::size_t bytes)
{
m_ec = m_cb.get().on_url (in, bytes);
return m_ec ? 1 : 0;
}
int
raw_parser::do_status (char const* in, std::size_t bytes)
{
auto const p (reinterpret_cast <joyent::http_parser const*> (&m_state));
m_ec = m_cb.get().on_status (p->status_code, in, bytes);
return m_ec ? 1 : 0;
}
int
raw_parser::do_header_field (char const* in, std::size_t bytes)
{
m_ec = m_cb.get().on_header_field (in, bytes);
return m_ec ? 1 : 0;
}
int
raw_parser::do_header_value (char const* in, std::size_t bytes)
{
m_ec = m_cb.get().on_header_value (in, bytes);
return m_ec ? 1 : 0;
}
int
raw_parser::do_headers_done ()
{
auto const p (reinterpret_cast <joyent::http_parser const*> (&m_state));
bool const keep_alive (joyent::http_should_keep_alive (p) != 0);
m_ec = m_cb.get().on_headers_done (keep_alive);
return m_ec ? 1 : 0;
}
int
raw_parser::do_body (char const* in, std::size_t bytes)
{
auto const p (reinterpret_cast <joyent::http_parser const*> (&m_state));
bool const is_final (
joyent::http_body_is_final (p) != 0);
m_ec = m_cb.get().on_body (is_final, in, bytes);
return m_ec ? 1 : 0;
}
int
raw_parser::do_message_complete ()
{
auto const p (reinterpret_cast <joyent::http_parser const*> (&m_state));
bool const keep_alive (joyent::http_should_keep_alive (p) != 0);
m_ec = m_cb.get().on_message_complete (keep_alive);
return m_ec ? 1 : 0;
}
//------------------------------------------------------------------------------
int
raw_parser::on_message_start (joyent::http_parser* p)
{
return reinterpret_cast <raw_parser*> (
p->data)->do_message_start();
}
int
raw_parser::on_url (joyent::http_parser* p,
char const* in, std::size_t bytes)
{
return reinterpret_cast <raw_parser*> (
p->data)->do_url (in, bytes);
}
int
raw_parser::on_status (joyent::http_parser* p,
char const* in, std::size_t bytes)
{
return reinterpret_cast <raw_parser*> (
p->data)->do_status (in, bytes);
}
int
raw_parser::on_header_field (joyent::http_parser* p,
char const* in, std::size_t bytes)
{
return reinterpret_cast <raw_parser*> (
p->data)->do_header_field (in, bytes);
}
int
raw_parser::on_header_value (joyent::http_parser* p,
char const* in, std::size_t bytes)
{
return reinterpret_cast <raw_parser*> (
p->data)->do_header_value (in, bytes);
}
int
raw_parser::on_headers_done (joyent::http_parser* p)
{
return reinterpret_cast <raw_parser*> (
p->data)->do_headers_done();
}
int
raw_parser::on_body (joyent::http_parser* p,
char const* in, std::size_t bytes)
{
return reinterpret_cast <raw_parser*> (
p->data)->do_body (
in, bytes);
}
int
raw_parser::on_message_complete (joyent::http_parser* p)
{
return reinterpret_cast <raw_parser*> (
p->data)->do_message_complete();
}
//------------------------------------------------------------------------------
auto
raw_parser::callback::on_request () ->
error_code
{
return error_code();
}
auto
raw_parser::callback::on_response () ->
error_code
{
return error_code();
}
auto
raw_parser::callback::on_url(
void const*, std::size_t) ->
error_code
{
return error_code();
}
auto
raw_parser::callback::on_status (int,
void const*, std::size_t) ->
error_code
{
return error_code();
}
auto
raw_parser::callback::on_header_field (
void const*, std::size_t) ->
error_code
{
return error_code();
}
auto
raw_parser::callback::on_header_value (
void const*, std::size_t) ->
error_code
{
return error_code();
}
auto
raw_parser::callback::on_headers_done (
bool) ->
error_code
{
return error_code();
}
auto
raw_parser::callback::on_body (
bool, void const*, std::size_t) ->
error_code
{
return error_code();
}
auto
raw_parser::callback::on_message_complete (
bool) ->
error_code
{
return error_code();
}
}
}

View File

@@ -48,6 +48,10 @@ enum class method_t
http_proppatch, http_proppatch,
http_search, http_search,
http_unlock, http_unlock,
http_bind,
http_rebind,
http_unbind,
http_acl,
// subversion // subversion
http_report, http_report,
@@ -63,7 +67,14 @@ enum class method_t
// RFC-5789 // RFC-5789
http_patch, http_patch,
http_purge http_purge,
// CalDav
http_mkcalendar,
// RFC-2068, section 19.6.1.2
http_link,
http_unlink
}; };
std::string std::string

View File

@@ -1,202 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HTTP_RAW_PARSER_H_INCLUDED
#define BEAST_HTTP_RAW_PARSER_H_INCLUDED
#include <beast/utility/empty_base_optimization.h>
#include <boost/system/error_code.hpp> // change to <system_error> soon
#include <array>
#include <cstdint>
#include <memory>
namespace beast {
namespace joyent {
struct http_parser;
};
namespace http {
/** Raw HTTP message parser.
This is implemented using a zero-allocation state machine. The caller
is responsible for all buffer management.
*/
class raw_parser
{
private:
using error_code = boost::system::error_code;
public:
enum message_type
{
request,
response
};
struct callback
{
/** Called when the first byte of an HTTP request is received. */
virtual
error_code
on_request ();
/** Called when the first byte of an HTTP response is received. */
virtual
error_code
on_response ();
/** Called repeatedly to provide parts of the URL.
This is only for requests.
*/
virtual
error_code
on_url (
void const* in, std::size_t bytes);
/** Called when the status is received.
This is only for responses.
*/
virtual
error_code
on_status (int status_code,
void const* in, std::size_t bytes);
/** Called repeatedly to provide parts of a field. */
virtual
error_code
on_header_field (
void const* in, std::size_t bytes);
/** Called repeatedly to provide parts of a value. */
virtual
error_code
on_header_value (
void const* in, std::size_t bytes);
/** Called when there are no more bytes of headers remaining. */
virtual
error_code
on_headers_done (
bool keep_alive);
/** Called repeatedly to provide parts of the body. */
virtual
error_code
on_body (bool is_final,
void const* in, std::size_t bytes);
/** Called when there are no more bytes of body remaining. */
virtual
error_code on_message_complete (
bool keep_alive);
};
explicit raw_parser (callback& cb);
~raw_parser();
/** Prepare to parse a new message.
The previous state information, if any, is discarded.
*/
void
reset (message_type type);
/** Processs message data.
The return value includes the error code if any,
and the number of bytes consumed in the input sequence.
*/
std::pair <error_code, std::size_t>
process_data (void const* in, std::size_t bytes);
/** Notify the parser the end of the data is reached.
Normally this will be called in response to the remote
end closing down its half of the connection.
*/
error_code
process_eof ();
private:
int do_message_start ();
int do_url (char const* in, std::size_t bytes);
int do_status (char const* in, std::size_t bytes);
int do_header_field (char const* in, std::size_t bytes);
int do_header_value (char const* in, std::size_t bytes);
int do_headers_done ();
int do_body (char const* in, std::size_t bytes);
int do_message_complete ();
static int on_message_start (joyent::http_parser*);
static int on_url (joyent::http_parser*, char const*, std::size_t);
static int on_status (joyent::http_parser*, char const*, std::size_t);
static int on_header_field (joyent::http_parser*, char const*, std::size_t);
static int on_header_value (joyent::http_parser*, char const*, std::size_t);
static int on_headers_done (joyent::http_parser*);
static int on_body (joyent::http_parser*, char const*, std::size_t);
static int on_message_complete (joyent::http_parser*);
// These structures must exactly match the
// declarations in joyent http_parser.h include
//
struct state_t
{
unsigned int type : 2;
unsigned int flags : 6;
unsigned int state : 8;
unsigned int header_state : 8;
unsigned int index : 8;
std::uint32_t nread;
std::uint64_t content_length;
unsigned short http_major;
unsigned short http_minor;
unsigned int status_code : 16;
unsigned int method : 8;
unsigned int http_errno : 7;
unsigned int upgrade : 1;
void *data;
};
using data_cb_t = int (*) (
state_t*, const char *at, size_t length);
using cb_t = int (*) (state_t*);
struct hooks_t
{
cb_t on_message_begin;
data_cb_t on_url;
data_cb_t on_status;
data_cb_t on_header_field;
data_cb_t on_header_value;
cb_t on_headers_complete;
data_cb_t on_body;
cb_t on_message_complete;
};
std::reference_wrapper <callback> m_cb;
error_code m_ec;
char m_state [sizeof(state_t)];
char m_hooks [sizeof(hooks_t)];
};
}
}
#endif

View File

@@ -65,6 +65,7 @@ public:
void void
notify (std::chrono::duration <Rep, Period> const& value) const notify (std::chrono::duration <Rep, Period> const& value) const
{ {
using namespace std::chrono;
if (m_impl) if (m_impl)
m_impl->notify (ceil <value_type> (value)); m_impl->notify (ceil <value_type> (value));
} }

View File

@@ -218,7 +218,7 @@ private:
} }
// VFALCO TODO IPv6 support // VFALCO TODO IPv6 support
bassertfalse; assert(false);
return boost::asio::ip::udp::endpoint ( return boost::asio::ip::udp::endpoint (
boost::asio::ip::address_v6 (), 0); boost::asio::ip::address_v6 (), 0);
} }

View File

@@ -71,6 +71,11 @@ struct is_call_possible_udt2
int operator()(int) const; int operator()(int) const;
}; };
struct is_call_possible_udt3
{
int operator()(int);
};
static_assert(is_call_possible< static_assert(is_call_possible<
is_call_possible_udt1, void(int)>::value, ""); is_call_possible_udt1, void(int)>::value, "");
@@ -86,6 +91,11 @@ static_assert(! is_call_possible<
static_assert(! is_call_possible< static_assert(! is_call_possible<
is_call_possible_udt2, void(void)>::value, ""); is_call_possible_udt2, void(void)>::value, "");
static_assert(is_call_possible<
is_call_possible_udt3, int(int)>::value, "");
static_assert(! is_call_possible<
is_call_possible_udt3 const, int(int)>::value, "");
} }
} }

View File

@@ -1,44 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_BOOSTINCLUDES_H_INCLUDED
#define BEAST_MODULE_ASIO_BOOSTINCLUDES_H_INCLUDED
// Make sure we take care of fixing boost::bind oddities first.
#if !defined(BEAST_CORE_H_INCLUDED)
#error core.h must be included before including this file
#endif
// These should have already been set in your project, but
// if you forgot then we will be optimistic and choose the latest.
//
#if BEAST_WIN32
# ifndef _WIN32_WINNT
# pragma message ("Warning: _WIN32_WINNT was not set in your project")
# define _WIN32_WINNT 0x0600
# endif
# ifndef _VARIADIC_MAX
# define _VARIADIC_MAX 10
# endif
#endif
// work-around for broken <boost/get_pointer.hpp>
#include <beast/boost/get_pointer.h>
#endif

View File

@@ -1,57 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/asio/HTTPField.h>
namespace beast {
HTTPField::HTTPField ()
{
}
HTTPField::HTTPField (String name_, String value_)
: m_name (name_)
, m_value (value_)
{
}
HTTPField::HTTPField (HTTPField const& other)
: m_name (other.m_name)
, m_value (other.m_value)
{
}
HTTPField& HTTPField::operator= (HTTPField const& other)
{
m_name = other.m_name;
m_value = other.m_value;
return *this;
}
String HTTPField::name () const
{
return m_name;
}
String HTTPField::value () const
{
return m_value;
}
}

View File

@@ -1,48 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPFIELD_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPFIELD_H_INCLUDED
#include <beast/strings/String.h>
namespace beast {
/** A single header.
The header is a field/value pair.
Time complexity of copies is constant.
*/
class HTTPField
{
public:
HTTPField ();
HTTPField (String name_, String value_);
HTTPField (HTTPField const& other);
HTTPField& operator= (HTTPField const& other);
String name () const;
String value () const;
private:
String m_name;
String m_value;
};
}
#endif

View File

@@ -1,108 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/asio/HTTPHeaders.h>
#include <algorithm>
namespace beast {
HTTPHeaders::HTTPHeaders ()
{
}
HTTPHeaders::HTTPHeaders (StringPairArray& fields)
{
m_fields.swapWith (fields);
}
HTTPHeaders::HTTPHeaders (StringPairArray const& fields)
: m_fields (fields)
{
}
HTTPHeaders::HTTPHeaders (HTTPHeaders const& other)
: m_fields (other.m_fields)
{
}
HTTPHeaders& HTTPHeaders::operator= (HTTPHeaders const& other)
{
m_fields = other.m_fields;
return *this;
}
bool HTTPHeaders::empty () const
{
return m_fields.size () == 0;
}
std::size_t HTTPHeaders::size () const
{
return m_fields.size ();
}
HTTPField HTTPHeaders::at (int index) const
{
return HTTPField (m_fields.getAllKeys () [index],
m_fields.getAllValues () [index]);
}
HTTPField HTTPHeaders::operator[] (int index) const
{
return at (index);
}
String HTTPHeaders::get (String const& field) const
{
return m_fields [field];
}
String HTTPHeaders::operator[] (String const& field) const
{
return get (field);
}
String HTTPHeaders::toString () const
{
String s;
for (int i = 0; i < m_fields.size (); ++i)
{
HTTPField const field (at(i));
s << field.name() << ": " << field.value() << newLine;
}
return s;
}
std::map <std::string, std::string>
HTTPHeaders::build_map() const
{
std::map <std::string, std::string> c;
auto const& k (m_fields.getAllKeys());
auto const& v (m_fields.getAllValues());
for (std::size_t i = 0; i < m_fields.size(); ++i)
{
auto key (k[i].toStdString());
auto const value (v[i].toStdString());
std::transform (key.begin(), key.end(), key.begin(), ::tolower);
c[key] = value;
}
return c;
}
}

View File

@@ -1,83 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPHEADERS_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPHEADERS_H_INCLUDED
#include <beast/module/asio/HTTPField.h>
#include <beast/module/core/text/StringPairArray.h>
#include <map>
namespace beast {
/** A set of HTTP headers. */
class HTTPHeaders
{
public:
/** Construct an empty set of headers. */
HTTPHeaders ();
/** Construct headers taking ownership of a field array.
The callers value is overwritten.
*/
HTTPHeaders (StringPairArray& fields);
/** Construct a copy of headers from an array.*/
HTTPHeaders (StringPairArray const& fields);
/** Construct a copy of headers. */
HTTPHeaders (HTTPHeaders const& other);
/** Assign a copy of headers. */
HTTPHeaders& operator= (HTTPHeaders const& other);
/** Returns `true` if the container is empty. */
bool empty () const;
/** Returns the number of fields in the container. */
std::size_t size () const;
/** Random access to fields by index. */
/** @{ */
HTTPField at (int index) const;
HTTPField operator[] (int index) const;
/** @} */
/** Associative access to fields by name.
If the field is not present, an empty string is returned.
*/
/** @{ */
String get (String const& field) const;
String operator[] (String const& field) const;
/** @} */
/** Outputs all the headers into one string. */
String toString () const;
// VFALCO HACK to present the headers in a useful format
std::map <std::string, std::string>
build_map() const;
private:
StringPairArray m_fields;
};
}
#endif

View File

@@ -1,56 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/asio/HTTPMessage.h>
namespace beast {
HTTPMessage::HTTPMessage (HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body)
: m_version (version_)
, m_headers (fields)
{
m_body.swapWith (body);
}
HTTPVersion const& HTTPMessage::version () const
{
return m_version;
}
HTTPHeaders const& HTTPMessage::headers () const
{
return m_headers;
}
DynamicBuffer const& HTTPMessage::body () const
{
return m_body;
}
String HTTPMessage::toString () const
{
String s;
s << "HTTP " << version().toString() << newLine;
s << m_headers.toString ();
return s;
}
}

View File

@@ -1,74 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPMESSAGE_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPMESSAGE_H_INCLUDED
#include <beast/module/asio/HTTPHeaders.h>
#include <beast/module/asio/HTTPVersion.h>
#include <beast/smart_ptr/SharedObject.h>
#include <beast/net/DynamicBuffer.h>
#include <beast/module/core/text/StringPairArray.h>
namespace beast {
/** A complete HTTP message.
This provides the information common to all HTTP messages, including
the version, content body, and headers.
Derived classes provide the request or response specific data.
Because a single HTTP message can be a fairly expensive object to
make copies of, this is a SharedObject.
@see HTTPRequest, HTTPResponse
*/
class HTTPMessage : public SharedObject
{
public:
/** Construct the common HTTP message parts from values.
Ownership of the fields and body parameters are
transferred from the caller.
*/
HTTPMessage (HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body);
/** Returns the HTTP version of this message. */
HTTPVersion const& version () const;
/** Returns the set of HTTP headers associated with this message. */
HTTPHeaders const& headers () const;
/** Returns the content-body. */
DynamicBuffer const& body () const;
/** Outputs all the HTTPMessage data excluding the body into a string. */
String toString () const;
private:
HTTPVersion m_version;
HTTPHeaders m_headers;
DynamicBuffer m_body;
};
}
#endif

View File

@@ -1,111 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/asio/HTTPParser.h>
#include <beast/module/asio/HTTPParserImpl.h>
namespace beast {
HTTPParser::HTTPParser (Type type)
: m_type (type)
, m_impl (new HTTPParserImpl (
(type == typeResponse) ? joyent::HTTP_RESPONSE : joyent::HTTP_REQUEST))
{
}
HTTPParser::~HTTPParser ()
{
}
unsigned char HTTPParser::error () const
{
return m_impl->http_errno ();
}
String HTTPParser::message () const
{
return m_impl->http_errno_message ();
}
std::size_t HTTPParser::process (void const* buf, std::size_t bytes)
{
std::size_t const bytes_used (m_impl->process (buf, bytes));
if (m_impl->finished ())
{
if (m_type == typeRequest)
{
m_request = new HTTPRequest (
m_impl->version (),
m_impl->fields (),
m_impl->body (),
m_impl->method ());
}
else if (m_type == typeResponse)
{
m_response = new HTTPResponse (
m_impl->version (),
m_impl->fields (),
m_impl->body (),
m_impl->status_code ());
}
else
{
bassertfalse;
}
}
return bytes_used;
}
void HTTPParser::process_eof ()
{
m_impl->process_eof ();
}
bool HTTPParser::finished () const
{
return m_impl->finished();
}
StringPairArray const& HTTPParser::fields () const
{
return m_impl->fields();
}
bool HTTPParser::headersComplete () const
{
return m_impl->headers_complete();
}
SharedPtr <HTTPRequest> const& HTTPParser::request ()
{
bassert (m_type == typeRequest);
return m_request;
}
SharedPtr <HTTPResponse> const& HTTPParser::response ()
{
bassert (m_type == typeResponse);
return m_response;
}
}

View File

@@ -1,92 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPPARSER_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPPARSER_H_INCLUDED
#include <beast/module/asio/HTTPRequest.h>
#include <beast/module/asio/HTTPResponse.h>
namespace beast {
class HTTPParserImpl;
/** A parser for HTTPRequest and HTTPResponse objects. */
class HTTPParser
{
public:
enum Type
{
typeRequest,
typeResponse
};
/** Construct a new parser for the specified HTTPMessage type. */
explicit HTTPParser (Type type);
/** Destroy the parser. */
~HTTPParser ();
/** Returns a non zero error code if parsing fails. */
unsigned char error () const;
/** Returns the error message text when error is non zero. */
String message () const;
/** Parse the buffer and return the amount used.
Typically it is an error when this returns less than
the amount passed in.
*/
std::size_t process (void const* buf, std::size_t bytes);
/** Notify the parser that eof was received.
*/
void process_eof ();
/** Returns `true` when parsing is successful and complete. */
bool finished () const;
/** Peek at the header fields as they are being built.
Only complete pairs will show up, never partial strings.
*/
StringPairArray const& fields () const;
/** Returns `true` if all the HTTP headers have been received. */
bool headersComplete () const;
/** Return the HTTPRequest object produced from the parsiing.
Only valid after finished returns `true`.
*/
SharedPtr <HTTPRequest> const& request ();
/** Return the HTTPResponse object produced from the parsing.
Only valid after finished returns `true`.
*/
SharedPtr <HTTPResponse> const& response ();
protected:
Type m_type;
std::unique_ptr <HTTPParserImpl> m_impl;
SharedPtr <HTTPRequest> m_request;
SharedPtr <HTTPResponse> m_response;
};
}
#endif

View File

@@ -1,276 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPPARSERIMPL_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPPARSERIMPL_H_INCLUDED
#include <beast/http/impl/joyent_parser.h>
#include <boost/asio/buffer.hpp>
namespace beast {
class HTTPParserImpl
{
public:
enum
{
stringReservation = 256
};
explicit HTTPParserImpl (enum joyent::http_parser_type type)
: m_finished (false)
, m_was_value (false)
, m_headersComplete (false)
{
m_settings.on_message_begin = &HTTPParserImpl::on_message_begin;
m_settings.on_url = &HTTPParserImpl::on_url;
m_settings.on_status = &HTTPParserImpl::on_status;
m_settings.on_header_field = &HTTPParserImpl::on_header_field;
m_settings.on_header_value = &HTTPParserImpl::on_header_value;
m_settings.on_headers_complete = &HTTPParserImpl::on_headers_complete;
m_settings.on_body = &HTTPParserImpl::on_body;
m_settings.on_message_complete = &HTTPParserImpl::on_message_complete;
m_field.reserve (stringReservation);
m_value.reserve (stringReservation);
joyent::http_parser_init (&m_parser, type);
m_parser.data = this;
}
~HTTPParserImpl ()
{
}
unsigned char error () const
{
return m_parser.http_errno;
}
String message () const
{
return String (joyent::http_errno_name (static_cast <
enum joyent::http_errno> (m_parser.http_errno)));
}
std::size_t process (void const* buf, std::size_t bytes)
{
return joyent::http_parser_execute (&m_parser,
&m_settings, static_cast <char const*> (buf), bytes);
}
void process_eof ()
{
joyent::http_parser_execute (&m_parser, &m_settings, nullptr, 0);
}
bool finished () const
{
return m_finished;
}
HTTPVersion version () const
{
return HTTPVersion (
m_parser.http_major, m_parser.http_minor);
}
// Only for HTTPResponse!
unsigned short status_code () const
{
return m_parser.status_code;
}
// Only for HTTPRequest!
unsigned char method () const
{
return m_parser.method;
}
unsigned char http_errno () const
{
return m_parser.http_errno;
}
String http_errno_message () const
{
return String (joyent::http_errno_name (
static_cast <enum joyent::http_errno> (
m_parser.http_errno)));
}
bool upgrade () const
{
return m_parser.upgrade != 0;
}
StringPairArray& fields ()
{
return m_fields;
}
bool headers_complete () const
{
return m_headersComplete;
}
DynamicBuffer& body ()
{
return m_body;
}
private:
void addFieldValue ()
{
if (m_field.size () > 0 && m_value.size () > 0)
m_fields.set (m_field, m_value);
m_field.resize (0);
m_value.resize (0);
}
int onMessageBegin ()
{
int ec (0);
return ec;
}
int onUrl (char const*, std::size_t)
{
int ec (0);
// This is for HTTP Request
return ec;
}
int onStatus ()
{
int ec (0);
return ec;
}
int onHeaderField (char const* at, std::size_t length)
{
int ec (0);
if (m_was_value)
{
addFieldValue ();
m_was_value = false;
}
m_field.append (at, length);
return ec;
}
int onHeaderValue (char const* at, std::size_t length)
{
int ec (0);
m_value.append (at, length);
m_was_value = true;
return ec;
}
int onHeadersComplete ()
{
m_headersComplete = true;
int ec (0);
addFieldValue ();
return ec;
}
int onBody (char const* at, std::size_t length)
{
m_body.commit (boost::asio::buffer_copy (
m_body.prepare <boost::asio::mutable_buffer> (length),
boost::asio::buffer (at, length)));
return 0;
}
int onMessageComplete ()
{
int ec (0);
m_finished = true;
return ec;
}
private:
static int on_message_begin (joyent::http_parser* parser)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onMessageBegin ();
}
static int on_url (joyent::http_parser* parser, const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onUrl (at, length);
}
static int on_status (joyent::http_parser* parser,
char const* /*at*/, size_t /*length*/)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onStatus ();
}
static int on_header_field (joyent::http_parser* parser,
const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeaderField (at, length);
}
static int on_header_value (joyent::http_parser* parser,
const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeaderValue (at, length);
}
static int on_headers_complete (joyent::http_parser* parser)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeadersComplete ();
}
static int on_body (joyent::http_parser* parser,
const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onBody (at, length);
}
static int on_message_complete (joyent::http_parser* parser)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onMessageComplete ();
}
private:
bool m_finished;
joyent::http_parser_settings m_settings;
joyent::http_parser m_parser;
StringPairArray m_fields;
bool m_was_value;
std::string m_field;
std::string m_value;
bool m_headersComplete;
DynamicBuffer m_body;
};
}
#endif

View File

@@ -1,47 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/asio/HTTPRequest.h>
namespace beast {
HTTPRequest::HTTPRequest (
HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body,
unsigned short method_)
: HTTPMessage (version_, fields, body)
, m_method (method_)
{
}
unsigned short HTTPRequest::method () const
{
return m_method;
}
String HTTPRequest::toString () const
{
String s;
s << "Method: " << String::fromNumber (method ()) << newLine;
s << this->HTTPMessage::toString ();
return s;
}
}

View File

@@ -1,51 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPREQUEST_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPREQUEST_H_INCLUDED
#include <beast/module/asio/HTTPMessage.h>
namespace beast {
class HTTPRequest : public HTTPMessage
{
public:
/** Construct a complete response from values.
Ownership of the fields and body parameters are
transferred from the caller.
*/
HTTPRequest (
HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body,
unsigned short method_);
unsigned short method () const;
/** Convert the request into a string, excluding the body. */
String toString () const;
private:
unsigned short m_method;
};
}
#endif

View File

@@ -1,38 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/asio/HTTPRequestParser.h>
namespace beast {
HTTPRequestParser::HTTPRequestParser ()
: HTTPParser (typeRequest)
{
}
HTTPRequestParser::~HTTPRequestParser ()
{
}
SharedPtr <HTTPRequest> const& HTTPRequestParser::request ()
{
return m_request;
}
}

View File

@@ -1,46 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPREQUESTPARSER_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPREQUESTPARSER_H_INCLUDED
#include <beast/module/asio/HTTPParser.h>
namespace beast {
/** A parser for HTTPRequest objects. */
class HTTPRequestParser : public HTTPParser
{
public:
/** Construct a new parser for the specified HTTPMessage type. */
HTTPRequestParser ();
/** Destroy the parser. */
~HTTPRequestParser ();
/** Return the HTTPRequest object produced from the parsing. */
SharedPtr <HTTPRequest> const& request ();
private:
//SharedPtr <HTTPRequest> m_request;
};
}
#endif

View File

@@ -1,47 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/asio/HTTPResponse.h>
namespace beast {
HTTPResponse::HTTPResponse (
HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body,
unsigned short status_)
: HTTPMessage (version_, fields, body)
, m_status (status_)
{
}
unsigned short HTTPResponse::status () const
{
return m_status;
}
String HTTPResponse::toString () const
{
String s;
s << "Status: " << String::fromNumber (status ()) << newLine;
s << this->HTTPMessage::toString ();
return s;
}
}

View File

@@ -1,51 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPRESPONSE_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPRESPONSE_H_INCLUDED
#include <beast/module/asio/HTTPMessage.h>
namespace beast {
class HTTPResponse : public HTTPMessage
{
public:
/** Construct a complete response from values.
Ownership of the fields and body parameters are
transferred from the caller.
*/
HTTPResponse (
HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body,
unsigned short status_);
unsigned short status () const;
/** Convert the response into a string, excluding the body. */
String toString () const;
private:
unsigned short m_status;
};
}
#endif

View File

@@ -1,38 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/module/asio/HTTPResponseParser.h>
namespace beast {
HTTPResponseParser::HTTPResponseParser ()
: HTTPParser (typeResponse)
{
}
HTTPResponseParser::~HTTPResponseParser ()
{
}
SharedPtr <HTTPResponse> const& HTTPResponseParser::response ()
{
return m_response;
}
}

View File

@@ -1,46 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPRESPONSEPARSER_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPRESPONSEPARSER_H_INCLUDED
#include <beast/module/asio/HTTPParser.h>
namespace beast {
/** A parser for HTTPResponse objects. */
class HTTPResponseParser : public HTTPParser
{
public:
/** Construct a new parser for the specified HTTPMessage type. */
HTTPResponseParser ();
/** Destroy the parser. */
~HTTPResponseParser ();
/** Return the HTTPResponse object produced from the parsing. */
SharedPtr <HTTPResponse> const& response ();
private:
//SharedPtr <HTTPResponse> m_response;
};
}
#endif

View File

@@ -1,97 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
HTTPVersion::HTTPVersion ()
: m_major (0)
, m_minor (0)
{
}
HTTPVersion::HTTPVersion (unsigned short major_, unsigned short minor_)
: m_major (major_)
, m_minor (minor_)
{
}
HTTPVersion::HTTPVersion (HTTPVersion const& other)
: m_major (other.m_major)
, m_minor (other.m_minor)
{
}
HTTPVersion& HTTPVersion::operator= (HTTPVersion const& other)
{
m_major = other.m_major;
m_minor = other.m_minor;
return *this;
}
String HTTPVersion::toString () const
{
return String::fromNumber (vmajor ()) + "." +
String::fromNumber (vminor ());
}
unsigned short HTTPVersion::vmajor () const
{
return m_major;
}
unsigned short HTTPVersion::vminor () const
{
return m_minor;
}
bool HTTPVersion::operator== (HTTPVersion const& rhs) const
{
return (m_major == rhs.m_major) && (m_minor == rhs.m_minor);
}
bool HTTPVersion::operator!= (HTTPVersion const& rhs) const
{
return (m_major != rhs.m_major) || (m_minor != rhs.m_minor);
}
bool HTTPVersion::operator> (HTTPVersion const& rhs) const
{
return (m_major > rhs.m_major) ||
((m_major == rhs.m_major) && (m_minor > rhs.m_minor));
}
bool HTTPVersion::operator>= (HTTPVersion const& rhs) const
{
return (m_major > rhs.m_major) ||
((m_major == rhs.m_major) && (m_minor >= rhs.m_minor));
}
bool HTTPVersion::operator< (HTTPVersion const& rhs) const
{
return (m_major < rhs.m_major) ||
((m_major == rhs.m_major) && (m_minor < rhs.m_minor));
}
bool HTTPVersion::operator<= (HTTPVersion const& rhs) const
{
return (m_major < rhs.m_major) ||
((m_major == rhs.m_major) && (m_minor <= rhs.m_minor));
}
}

View File

@@ -1,50 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_HTTPVERSION_H_INCLUDED
#define BEAST_MODULE_ASIO_HTTPVERSION_H_INCLUDED
namespace beast {
/** The HTTP version. This is the major.minor version number. */
class HTTPVersion
{
public:
HTTPVersion ();
HTTPVersion (unsigned short major_, unsigned short minor_);
HTTPVersion (HTTPVersion const& other);
HTTPVersion& operator= (HTTPVersion const& other);
String toString () const;
unsigned short vmajor () const;
unsigned short vminor () const;
bool operator== (HTTPVersion const& rhs) const;
bool operator!= (HTTPVersion const& rhs) const;
bool operator> (HTTPVersion const& rhs) const;
bool operator>= (HTTPVersion const& rhs) const;
bool operator< (HTTPVersion const& rhs) const;
bool operator<= (HTTPVersion const& rhs) const;
private:
unsigned short m_major;
unsigned short m_minor;
};
}
#endif

View File

@@ -1,40 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_ASIO_OPENSSLINCLUDES_H_INCLUDED
#define BEAST_MODULE_ASIO_OPENSSLINCLUDES_H_INCLUDED
#define OPENSSL_THREAD_DEFINES
#include <openssl/opensslconf.h>
//------------------------------------------------------------------------------
// Configure our settings based on what we find
//
#if defined(OPENSSL_THREADS)
# ifndef BEAST_OPENSSL_MULTITHREADED
# define BEAST_OPENSSL_MULTITHREADED 1
# endif
#else
# ifndef BEAST_OPENSSL_MULTITHREADED
# define BEAST_OPENSSL_MULTITHREADED 0
# endif
#endif
#endif

View File

@@ -1,32 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#if BEAST_INCLUDE_BEASTCONFIG
#include <BeastConfig.h>
#endif
#include <beast/module/asio/HTTPField.cpp>
#include <beast/module/asio/HTTPHeaders.cpp>
#include <beast/module/asio/HTTPMessage.cpp>
#include <beast/module/asio/HTTPRequest.cpp>
#include <beast/module/asio/HTTPResponse.cpp>
#include <beast/module/asio/HTTPVersion.cpp>
#include <beast/module/asio/HTTPParser.cpp>
#include <beast/module/asio/HTTPRequestParser.cpp>
#include <beast/module/asio/HTTPResponseParser.cpp>

File diff suppressed because it is too large Load Diff

View File

@@ -1,135 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_CORE_CONTAINERS_ARRAYALLOCATIONBASE_H_INCLUDED
#define BEAST_MODULE_CORE_CONTAINERS_ARRAYALLOCATIONBASE_H_INCLUDED
#include <beast/HeapBlock.h>
namespace beast {
//==============================================================================
/**
Implements some basic array storage allocation functions.
This class isn't really for public use - it's used by the other
array classes, but might come in handy for some purposes.
It inherits from a critical section class to allow the arrays to use
the "empty base class optimisation" pattern to reduce their footprint.
@see Array, SharedObjectArray
*/
template <class ElementType, class TypeOfCriticalSectionToUse>
class ArrayAllocationBase
: public TypeOfCriticalSectionToUse
{
public:
//==============================================================================
/** Creates an empty array. */
ArrayAllocationBase() noexcept
: numAllocated (0)
{
}
/** Destructor. */
~ArrayAllocationBase() noexcept
{
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
ArrayAllocationBase (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
: elements (static_cast <HeapBlock <ElementType>&&> (other.elements)),
numAllocated (other.numAllocated)
{
}
ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
{
elements = static_cast <HeapBlock <ElementType>&&> (other.elements);
numAllocated = other.numAllocated;
return *this;
}
#endif
//==============================================================================
/** Changes the amount of storage allocated.
This will retain any data currently held in the array, and either add or
remove extra space at the end.
@param numElements the number of elements that are needed
*/
void setAllocatedSize (const int numElements)
{
if (numAllocated != numElements)
{
if (numElements > 0)
elements.reallocate ((size_t) numElements);
else
elements.free_up();
numAllocated = numElements;
}
}
/** Increases the amount of storage allocated if it is less than a given amount.
This will retain any data currently held in the array, but will add
extra space at the end to make sure there it's at least as big as the size
passed in. If it's already bigger, no action is taken.
@param minNumElements the minimum number of elements that are needed
*/
void ensureAllocatedSize (const int minNumElements)
{
if (minNumElements > numAllocated)
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
bassert (numAllocated <= 0 || elements != nullptr);
}
/** Minimises the amount of storage allocated so that it's no more than
the given number of elements.
*/
void shrinkToNoMoreThan (const int maxNumElements)
{
if (maxNumElements < numAllocated)
setAllocatedSize (maxNumElements);
}
/** Swap the contents of two objects. */
void swapWith (ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse>& other) noexcept
{
elements.swapWith (other.elements);
std::swap (numAllocated, other.numAllocated);
}
//==============================================================================
HeapBlock <ElementType> elements;
int numAllocated;
};
} // beast
#endif // BEAST_ARRAYALLOCATIONBASE_H_INCLUDED

View File

@@ -1,195 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_CORE_CONTAINERS_ELEMENTCOMPARATOR_H_INCLUDED
#define BEAST_MODULE_CORE_CONTAINERS_ELEMENTCOMPARATOR_H_INCLUDED
#include <algorithm>
namespace beast {
#ifndef DOXYGEN
/** This is an internal helper class which converts a beast ElementComparator style
class (using a "compareElements" method) into a class that's compatible with
std::sort (i.e. using an operator() to compare the elements)
*/
template <typename ElementComparator>
struct SortFunctionConverter
{
SortFunctionConverter (ElementComparator& e) : comparator (e) {}
template <typename Type>
bool operator() (Type a, Type b) { return comparator.compareElements (a, b) < 0; }
private:
ElementComparator& comparator;
SortFunctionConverter& operator= (const SortFunctionConverter&);
};
#endif
//==============================================================================
/**
Sorts a range of elements in an array.
The comparator object that is passed-in must define a public method with the following
signature:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator an object which defines a compareElements() method
@param array the array to sort
@param firstElement the index of the first element of the range to be sorted
@param lastElement the index of the last element in the range that needs
sorting (this is inclusive)
@param retainOrderOfEquivalentItems if true, the order of items that the
comparator deems the same will be maintained - this will be
a slower algorithm than if they are allowed to be moved around.
@see sortArrayRetainingOrder
*/
template <class ElementType, class ElementComparator>
static void sortArray (ElementComparator& comparator,
ElementType* const array,
int firstElement,
int lastElement,
const bool retainOrderOfEquivalentItems)
{
SortFunctionConverter<ElementComparator> converter (comparator);
if (retainOrderOfEquivalentItems)
std::stable_sort (array + firstElement, array + lastElement + 1, converter);
else
std::sort (array + firstElement, array + lastElement + 1, converter);
}
//==============================================================================
/**
Searches a sorted array of elements, looking for the index at which a specified value
should be inserted for it to be in the correct order.
The comparator object that is passed-in must define a public method with the following
signature:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator an object which defines a compareElements() method
@param array the array to search
@param newElement the value that is going to be inserted
@param firstElement the index of the first element to search
@param lastElement the index of the last element in the range (this is non-inclusive)
*/
template <class ElementType, class ElementComparator>
static int findInsertIndexInSortedArray (ElementComparator& comparator,
ElementType* const array,
const ElementType newElement,
int firstElement,
int lastElement)
{
bassert (firstElement <= lastElement);
(void) comparator; // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
while (firstElement < lastElement)
{
if (comparator.compareElements (newElement, array [firstElement]) == 0)
{
++firstElement;
break;
}
else
{
const int halfway = (firstElement + lastElement) >> 1;
if (halfway == firstElement)
{
if (comparator.compareElements (newElement, array [halfway]) >= 0)
++firstElement;
break;
}
else if (comparator.compareElements (newElement, array [halfway]) >= 0)
{
firstElement = halfway;
}
else
{
lastElement = halfway;
}
}
}
return firstElement;
}
//==============================================================================
/**
A simple ElementComparator class that can be used to sort an array of
objects that support the '<' operator.
This will work for primitive types and objects that implement operator<().
Example: @code
Array <int> myArray;
DefaultElementComparator<int> sorter;
myArray.sort (sorter);
@endcode
@see ElementComparator
*/
template <class ElementType>
class DefaultElementComparator
{
private:
using ParameterType = ElementType;
public:
static int compareElements (ParameterType first, ParameterType second)
{
return (first < second) ? -1 : ((second < first) ? 1 : 0);
}
};
} // beast
#endif

View File

@@ -26,7 +26,6 @@
// TargetPlatform.h should not use anything from BeastConfig.h // TargetPlatform.h should not use anything from BeastConfig.h
#include <beast/Config.h> #include <beast/Config.h>
#include <beast/config/ContractChecks.h>
#if BEAST_MSVC #if BEAST_MSVC
# pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state) # pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
@@ -41,12 +40,10 @@
// New header-only library modeled more closely according to boost // New header-only library modeled more closely according to boost
#include <beast/SmartPtr.h> #include <beast/SmartPtr.h>
#include <beast/Arithmetic.h>
#include <beast/ByteOrder.h> #include <beast/ByteOrder.h>
#include <beast/HeapBlock.h> #include <beast/HeapBlock.h>
#include <beast/Memory.h> #include <beast/Memory.h>
#include <beast/Intrusive.h> #include <beast/Intrusive.h>
#include <beast/Strings.h>
#include <beast/Threads.h> #include <beast/Threads.h>
#include <beast/utility/Debug.h> #include <beast/utility/Debug.h>
@@ -55,91 +52,14 @@
#include <beast/module/core/system/StandardIncludes.h> #include <beast/module/core/system/StandardIncludes.h>
namespace beast
{
class InputStream;
class OutputStream;
class FileInputStream;
class FileOutputStream;
} // beast
// Order matters, since headers don't have their own #include lines. // Order matters, since headers don't have their own #include lines.
// Add new includes to the bottom. // Add new includes to the bottom.
#include <beast/module/core/time/Time.h>
#include <beast/module/core/threads/ScopedLock.h> #include <beast/module/core/threads/ScopedLock.h>
#include <beast/module/core/threads/CriticalSection.h>
#include <beast/module/core/containers/ElementComparator.h>
// If the MSVC debug heap headers were included, disable
// the macros during the juce include since they conflict.
#ifdef _CRTDBG_MAP_ALLOC
#pragma push_macro("calloc")
#pragma push_macro("free")
#pragma push_macro("malloc")
#pragma push_macro("realloc")
#pragma push_macro("_recalloc")
#pragma push_macro("_aligned_free")
#pragma push_macro("_aligned_malloc")
#pragma push_macro("_aligned_offset_malloc")
#pragma push_macro("_aligned_realloc")
#pragma push_macro("_aligned_recalloc")
#pragma push_macro("_aligned_offset_realloc")
#pragma push_macro("_aligned_offset_recalloc")
#pragma push_macro("_aligned_msize")
#undef calloc
#undef free
#undef malloc
#undef realloc
#undef _recalloc
#undef _aligned_free
#undef _aligned_malloc
#undef _aligned_offset_malloc
#undef _aligned_realloc
#undef _aligned_recalloc
#undef _aligned_offset_realloc
#undef _aligned_offset_recalloc
#undef _aligned_msize
#endif
#include <beast/module/core/containers/ArrayAllocationBase.h>
#ifdef _CRTDBG_MAP_ALLOC
#pragma pop_macro("_aligned_msize")
#pragma pop_macro("_aligned_offset_recalloc")
#pragma pop_macro("_aligned_offset_realloc")
#pragma pop_macro("_aligned_recalloc")
#pragma pop_macro("_aligned_realloc")
#pragma pop_macro("_aligned_offset_malloc")
#pragma pop_macro("_aligned_malloc")
#pragma pop_macro("_aligned_free")
#pragma pop_macro("_recalloc")
#pragma pop_macro("realloc")
#pragma pop_macro("malloc")
#pragma pop_macro("free")
#pragma pop_macro("calloc")
#endif
#include <beast/module/core/containers/Array.h>
#include <beast/module/core/misc/Result.h>
#include <beast/module/core/text/StringArray.h>
#include <beast/module/core/memory/MemoryBlock.h>
#include <beast/module/core/files/File.h>
#include <beast/module/core/thread/MutexTraits.h>
#include <beast/module/core/diagnostic/FatalError.h> #include <beast/module/core/diagnostic/FatalError.h>
#include <beast/module/core/text/LexicalCast.h> #include <beast/module/core/text/LexicalCast.h>
#include <beast/module/core/logging/Logger.h> #include <beast/module/core/logging/Logger.h>
#include <beast/module/core/maths/Random.h>
#include <beast/module/core/text/StringPairArray.h>
#include <beast/module/core/files/DirectoryIterator.h>
#include <beast/module/core/streams/InputStream.h>
#include <beast/module/core/files/FileInputStream.h>
#include <beast/module/core/streams/InputSource.h>
#include <beast/module/core/streams/OutputStream.h>
#include <beast/module/core/files/FileOutputStream.h>
#include <beast/module/core/streams/MemoryOutputStream.h>
#include <beast/module/core/system/SystemStats.h> #include <beast/module/core/system/SystemStats.h>
#include <beast/module/core/diagnostic/SemanticVersion.h> #include <beast/module/core/diagnostic/SemanticVersion.h>

View File

@@ -134,26 +134,9 @@
#include <beast/module/core/diagnostic/SemanticVersion.cpp> #include <beast/module/core/diagnostic/SemanticVersion.cpp>
#include <beast/module/core/diagnostic/UnitTestUtilities.cpp> #include <beast/module/core/diagnostic/UnitTestUtilities.cpp>
#include <beast/module/core/files/DirectoryIterator.cpp>
#include <beast/module/core/files/File.cpp>
#include <beast/module/core/files/FileInputStream.cpp>
#include <beast/module/core/files/FileOutputStream.cpp>
#include <beast/module/core/maths/Random.cpp>
#include <beast/module/core/memory/MemoryBlock.cpp>
#include <beast/module/core/misc/Result.cpp>
#include <beast/module/core/streams/InputStream.cpp>
#include <beast/module/core/streams/MemoryOutputStream.cpp>
#include <beast/module/core/streams/OutputStream.cpp>
#include <beast/module/core/system/SystemStats.cpp> #include <beast/module/core/system/SystemStats.cpp>
#include <beast/module/core/text/LexicalCast.cpp> #include <beast/module/core/text/LexicalCast.cpp>
#include <beast/module/core/text/StringArray.cpp>
#include <beast/module/core/text/StringPairArray.cpp>
#include <beast/module/core/thread/DeadlineTimer.cpp> #include <beast/module/core/thread/DeadlineTimer.cpp>
#include <beast/module/core/thread/Workers.cpp> #include <beast/module/core/thread/Workers.cpp>
@@ -168,26 +151,16 @@
#include "native/android_JNIHelpers.h" #include "native/android_JNIHelpers.h"
#endif #endif
#if ! BEAST_WINDOWS
#include <beast/module/core/native/posix_SharedCode.h>
#endif
#if BEAST_MAC || BEAST_IOS #if BEAST_MAC || BEAST_IOS
#include <beast/module/core/native/mac_Files.mm>
#include <beast/module/core/native/mac_Strings.mm>
#include <beast/module/core/native/mac_SystemStats.mm> #include <beast/module/core/native/mac_SystemStats.mm>
#elif BEAST_WINDOWS #elif BEAST_WINDOWS
#include <beast/module/core/native/win32_Files.cpp>
#include <beast/module/core/native/win32_SystemStats.cpp> #include <beast/module/core/native/win32_SystemStats.cpp>
#include <beast/module/core/native/win32_Threads.cpp>
#elif BEAST_LINUX #elif BEAST_LINUX
#include <beast/module/core/native/linux_Files.cpp>
#include <beast/module/core/native/linux_SystemStats.cpp> #include <beast/module/core/native/linux_SystemStats.cpp>
#elif BEAST_BSD #elif BEAST_BSD
#include <beast/module/core/native/bsd_Files.cpp>
#include <beast/module/core/native/bsd_SystemStats.cpp> #include <beast/module/core/native/bsd_SystemStats.cpp>
#elif BEAST_ANDROID #elif BEAST_ANDROID
@@ -198,17 +171,6 @@
#endif #endif
// Has to be outside the beast namespace
extern "C" {
void beast_reportFatalError (char const* message, char const* fileName, int lineNumber)
{
if (beast::beast_isRunningUnderDebugger())
beast_breakDebugger;
beast::FatalError (message, fileName, lineNumber);
BEAST_ANALYZER_NORETURN
}
}
#ifdef _CRTDBG_MAP_ALLOC #ifdef _CRTDBG_MAP_ALLOC
#pragma pop_macro("calloc") #pragma pop_macro("calloc")
#pragma pop_macro("free") #pragma pop_macro("free")

View File

@@ -20,8 +20,6 @@
#ifndef BEAST_MODULE_CORE_DIAGNOSTIC_FATALERROR_H_INCLUDED #ifndef BEAST_MODULE_CORE_DIAGNOSTIC_FATALERROR_H_INCLUDED
#define BEAST_MODULE_CORE_DIAGNOSTIC_FATALERROR_H_INCLUDED #define BEAST_MODULE_CORE_DIAGNOSTIC_FATALERROR_H_INCLUDED
#include <beast/strings/String.h>
namespace beast namespace beast
{ {

View File

@@ -21,6 +21,7 @@
#include <beast/module/core/text/LexicalCast.h> #include <beast/module/core/text/LexicalCast.h>
#include <algorithm> #include <algorithm>
#include <cassert>
namespace beast { namespace beast {
@@ -291,7 +292,7 @@ int compare (SemanticVersion const& lhs, SemanticVersion const& rhs)
if (isNumeric (left)) if (isNumeric (left))
{ {
bassert (isNumeric (right)); assert(isNumeric (right));
int const iLeft (lexicalCastThrow <int> (left)); int const iLeft (lexicalCastThrow <int> (left));
int const iRight (lexicalCastThrow <int> (right)); int const iRight (lexicalCastThrow <int> (right));
@@ -303,7 +304,7 @@ int compare (SemanticVersion const& lhs, SemanticVersion const& rhs)
} }
else else
{ {
bassert (! isNumeric (right)); assert (! isNumeric (right));
int result = left.compare (right); int result = left.compare (right);

View File

@@ -20,111 +20,51 @@
#ifndef BEAST_MODULE_CORE_DIAGNOSTIC_UNITTESTUTILITIES_H_INCLUDED #ifndef BEAST_MODULE_CORE_DIAGNOSTIC_UNITTESTUTILITIES_H_INCLUDED
#define BEAST_MODULE_CORE_DIAGNOSTIC_UNITTESTUTILITIES_H_INCLUDED #define BEAST_MODULE_CORE_DIAGNOSTIC_UNITTESTUTILITIES_H_INCLUDED
#include <beast/module/core/files/File.h> #include <boost/filesystem.hpp>
#include <beast/module/core/maths/Random.h> #include <string>
namespace beast { namespace beast {
namespace UnitTestUtilities { namespace UnitTestUtilities {
/** Fairly shuffle an array pseudo-randomly.
*/
template <class T>
void repeatableShuffle (int const numberOfItems, T& arrayOfItems, Random& r)
{
for (int i = numberOfItems - 1; i > 0; --i)
{
int const choice = r.nextInt (i + 1);
std::swap (arrayOfItems [i], arrayOfItems [choice]);
}
}
template <class T>
void repeatableShuffle (int const numberOfItems, T& arrayOfItems, std::int64_t seedValue)
{
Random r (seedValue);
repeatableShuffle (numberOfItems, arrayOfItems, r);
}
//------------------------------------------------------------------------------
/** A block of memory used for test data.
*/
struct Payload
{
/** Construct a payload with a buffer of the specified maximum size.
@param maximumBytes The size of the buffer, in bytes.
*/
explicit Payload (int maxBufferSize)
: bufferSize (maxBufferSize)
, data (maxBufferSize)
{
}
/** Generate a random block of data within a certain size range.
@param minimumBytes The smallest number of bytes in the resulting payload.
@param maximumBytes The largest number of bytes in the resulting payload.
@param seedValue The value to seed the random number generator with.
*/
void repeatableRandomFill (int minimumBytes, int maximumBytes, std::int64_t seedValue) noexcept
{
bassert (minimumBytes >=0 && maximumBytes <= bufferSize);
Random r (seedValue);
bytes = minimumBytes + r.nextInt (1 + maximumBytes - minimumBytes);
bassert (bytes >= minimumBytes && bytes <= bufferSize);
for (int i = 0; i < bytes; ++i)
data [i] = static_cast <unsigned char> (r.nextInt ());
}
/** Compare two payloads for equality.
*/
bool operator== (Payload const& other) const noexcept
{
if (bytes == other.bytes)
{
return memcmp (data.getData (), other.data.getData (), bytes) == 0;
}
else
{
return false;
}
}
public:
int const bufferSize;
int bytes;
HeapBlock <char> data;
};
class TempDirectory class TempDirectory
{ {
public: public:
explicit TempDirectory (std::string const& root) TempDirectory ()
: directory (File::createTempFile (root))
{ {
auto const tempDir =
boost::filesystem::temp_directory_path();
do
{
tempPath =
tempDir / boost::filesystem::unique_path();
} while (boost::filesystem::exists(tempPath));
boost::filesystem::create_directory (tempPath);
} }
~TempDirectory() ~TempDirectory()
{ {
directory.deleteRecursively(); boost::filesystem::remove_all (tempPath);
} }
String const& getFullPathName() const /** Returns the native path for the temporary folder */
std::string path() const
{ {
return directory.getFullPathName(); return tempPath.string();
}
/** Returns the native for the given file */
std::string file (std::string const& name) const
{
return (tempPath / name).string();
} }
TempDirectory(const TempDirectory&) = delete; TempDirectory(const TempDirectory&) = delete;
TempDirectory& operator=(const TempDirectory&) = delete; TempDirectory& operator=(const TempDirectory&) = delete;
private: private:
File const directory; boost::filesystem::path tempPath;
}; };
} // UnitTestUtilities } // UnitTestUtilities

View File

@@ -1,161 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <memory>
namespace beast {
static StringArray parseWildcards (const String& pattern)
{
StringArray s;
s.addTokens (pattern, ";,", "\"'");
s.trim();
s.removeEmptyStrings();
return s;
}
static bool fileMatches (const StringArray& wildCards, const String& filename)
{
for (int i = 0; i < wildCards.size(); ++i)
if (filename.matchesWildcard (wildCards[i], ! File::areFileNamesCaseSensitive()))
return true;
return false;
}
DirectoryIterator::DirectoryIterator (const File& directory, bool recursive,
const String& pattern, const int type)
: wildCards (parseWildcards (pattern)),
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
wildCard (pattern),
path (File::addTrailingSeparator (directory.getFullPathName())),
index (-1),
totalNumFiles (-1),
whatToLookFor (type),
isRecursive (recursive),
hasBeenAdvanced (false)
{
// you have to specify the type of files you're looking for!
bassert ((type & (File::findFiles | File::findDirectories)) != 0);
bassert (type > 0 && type <= 7);
}
DirectoryIterator::~DirectoryIterator()
{
}
bool DirectoryIterator::next()
{
return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
}
bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
hasBeenAdvanced = true;
if (subIterator != nullptr)
{
if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly))
return true;
subIterator = nullptr;
}
String filename;
bool isDirectory, isHidden = false;
while (fileFinder.next (filename, &isDirectory,
(isHiddenResult != nullptr || (whatToLookFor & File::ignoreHiddenFiles) != 0) ? &isHidden : nullptr,
fileSize, modTime, creationTime, isReadOnly))
{
++index;
if (! filename.containsOnly ("."))
{
bool matches = false;
if (isDirectory)
{
if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
subIterator = std::make_unique <DirectoryIterator> (
File::createFileWithoutCheckingPath (path + filename),
true, wildCard, whatToLookFor);
matches = (whatToLookFor & File::findDirectories) != 0;
}
else
{
matches = (whatToLookFor & File::findFiles) != 0;
}
// if we're not relying on the OS iterator to do the wildcard match, do it now..
if (matches && (isRecursive || wildCards.size() > 1))
matches = fileMatches (wildCards, filename);
if (matches && (whatToLookFor & File::ignoreHiddenFiles) != 0)
matches = ! isHidden;
if (matches)
{
currentFile = File::createFileWithoutCheckingPath (path + filename);
if (isHiddenResult != nullptr) *isHiddenResult = isHidden;
if (isDirResult != nullptr) *isDirResult = isDirectory;
return true;
}
if (subIterator != nullptr)
return next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly);
}
}
return false;
}
const File& DirectoryIterator::getFile() const
{
if (subIterator != nullptr && subIterator->hasBeenAdvanced)
return subIterator->getFile();
// You need to call DirectoryIterator::next() before asking it for the file that it found!
bassert (hasBeenAdvanced);
return currentFile;
}
float DirectoryIterator::getEstimatedProgress() const
{
if (totalNumFiles < 0)
totalNumFiles = File (path).getNumberOfChildFiles (File::findFilesAndDirectories);
if (totalNumFiles <= 0)
return 0.0f;
const float detailedIndex = (subIterator != nullptr) ? index + subIterator->getEstimatedProgress()
: (float) index;
return detailedIndex / totalNumFiles;
}
} // beast

View File

@@ -1,157 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_CORE_FILES_DIRECTORYITERATOR_H_INCLUDED
#define BEAST_MODULE_CORE_FILES_DIRECTORYITERATOR_H_INCLUDED
#include <memory>
namespace beast {
//==============================================================================
/**
Searches through a the files in a directory, returning each file that is found.
A DirectoryIterator will search through a directory and its subdirectories using
a wildcard filepattern match.
If you may be finding a large number of files, this is better than
using File::findChildFiles() because it doesn't block while it finds them
all, and this is more memory-efficient.
It can also guess how far it's got using a wildly inaccurate algorithm.
*/
class DirectoryIterator
{
public:
//==============================================================================
/** Creates a DirectoryIterator for a given directory.
After creating one of these, call its next() method to get the
first file - e.g. @code
DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose");
while (iter.next())
{
File theFileItFound (iter.getFile());
... etc
}
@endcode
@param directory the directory to search in
@param isRecursive whether all the subdirectories should also be searched
@param wildCard the file pattern to match. This may contain multiple patterns
separated by a semi-colon or comma, e.g. "*.jpg;*.png"
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying
whether to look for files, directories, or both.
*/
DirectoryIterator (const File& directory,
bool isRecursive,
const String& wildCard = "*",
int whatToLookFor = File::findFiles);
DirectoryIterator(DirectoryIterator const&) = delete;
DirectoryIterator& operator= (DirectoryIterator const&) = delete;
/** Destructor. */
~DirectoryIterator();
/** Moves the iterator along to the next file.
@returns true if a file was found (you can then use getFile() to see what it was) - or
false if there are no more matching files.
*/
bool next();
/** Moves the iterator along to the next file, and returns various properties of that file.
If you need to find out details about the file, it's more efficient to call this method than
to call the normal next() method and then find out the details afterwards.
All the parameters are optional, so pass null pointers for any items that you're not
interested in.
@returns true if a file was found (you can then use getFile() to see what it was) - or
false if there are no more matching files. If it returns false, then none of the
parameters will be filled-in.
*/
bool next (bool* isDirectory,
bool* isHidden,
std::int64_t* fileSize,
Time* modTime,
Time* creationTime,
bool* isReadOnly);
/** Returns the file that the iterator is currently pointing at.
The result of this call is only valid after a call to next() has returned true.
*/
const File& getFile() const;
/** Returns a guess of how far through the search the iterator has got.
@returns a value 0.0 to 1.0 to show the progress, although this won't be
very accurate.
*/
float getEstimatedProgress() const;
private:
//==============================================================================
class NativeIterator
{
public:
NativeIterator (const File& directory, const String& wildCard);
NativeIterator(NativeIterator const&) = delete;
NativeIterator& operator= (NativeIterator const&) = delete;
~NativeIterator();
bool next (String& filenameFound,
bool* isDirectory, bool* isHidden, std::int64_t* fileSize,
Time* modTime, Time* creationTime, bool* isReadOnly);
class Pimpl;
private:
friend class DirectoryIterator;
std::unique_ptr<Pimpl> pimpl;
};
StringArray wildCards;
NativeIterator fileFinder;
String wildCard, path;
int index;
mutable int totalNumFiles;
const int whatToLookFor;
const bool isRecursive;
bool hasBeenAdvanced;
std::unique_ptr <DirectoryIterator> subIterator;
File currentFile;
};
} // beast
#endif // BEAST_DIRECTORYITERATOR_H_INCLUDED

View File

@@ -1,525 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <algorithm>
#include <memory>
namespace beast {
File const& File::nonexistent()
{
static File const instance;
return instance;
}
//------------------------------------------------------------------------------
File::File (const String& fullPathName)
: fullPath (parseAbsolutePath (fullPathName))
{
}
File::File (const File& other)
: fullPath (other.fullPath)
{
}
File File::createFileWithoutCheckingPath (const String& path) noexcept
{
File f;
f.fullPath = path;
return f;
}
File& File::operator= (const String& newPath)
{
fullPath = parseAbsolutePath (newPath);
return *this;
}
File& File::operator= (const File& other)
{
fullPath = other.fullPath;
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
File::File (File&& other) noexcept
: fullPath (static_cast <String&&> (other.fullPath))
{
}
File& File::operator= (File&& other) noexcept
{
fullPath = static_cast <String&&> (other.fullPath);
return *this;
}
#endif
//==============================================================================
String File::parseAbsolutePath (const String& p)
{
if (p.isEmpty())
return String::empty;
#if BEAST_WINDOWS
// Windows..
String path (p.replaceCharacter ('/', '\\'));
if (path.startsWithChar (separator))
{
if (path[1] != separator)
{
/* When you supply a raw string to the File object constructor, it must be an absolute path.
If you're trying to parse a string that may be either a relative path or an absolute path,
you MUST provide a context against which the partial path can be evaluated - you can do
this by simply using File::getChildFile() instead of the File constructor. E.g. saying
"File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
path if that's what was supplied, or would evaluate a partial path relative to the CWD.
*/
bassertfalse;
path = File::getCurrentWorkingDirectory().getFullPathName().substring (0, 2) + path;
}
}
else if (! path.containsChar (':'))
{
/* When you supply a raw string to the File object constructor, it must be an absolute path.
If you're trying to parse a string that may be either a relative path or an absolute path,
you MUST provide a context against which the partial path can be evaluated - you can do
this by simply using File::getChildFile() instead of the File constructor. E.g. saying
"File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
path if that's what was supplied, or would evaluate a partial path relative to the CWD.
*/
bassertfalse;
return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
}
#else
// Mac or Linux..
// Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here
// to catch anyone who's trying to run code that was written on Windows with hard-coded path names.
// If that's why you've ended up here, use File::getChildFile() to build your paths instead.
bassert ((! p.containsChar ('\\')) || (p.indexOfChar ('/') >= 0 && p.indexOfChar ('/') < p.indexOfChar ('\\')));
String path (p);
if (path.startsWithChar ('~'))
{
if (path[1] == separator || path[1] == 0)
{
// expand a name of the form "~/abc"
path = File::getSpecialLocation (File::userHomeDirectory).getFullPathName()
+ path.substring (1);
}
else
{
// expand a name of type "~dave/abc"
const String userName (path.substring (1).upToFirstOccurrenceOf ("/", false, false));
if (struct passwd* const pw = getpwnam (userName.toUTF8()))
path = addTrailingSeparator (pw->pw_dir) + path.fromFirstOccurrenceOf ("/", false, false);
}
}
else if (! path.startsWithChar (separator))
{
#if BEAST_DEBUG || BEAST_LOG_ASSERTIONS
if (! (path.startsWith ("./") || path.startsWith ("../")))
{
/* When you supply a raw string to the File object constructor, it must be an absolute path.
If you're trying to parse a string that may be either a relative path or an absolute path,
you MUST provide a context against which the partial path can be evaluated - you can do
this by simply using File::getChildFile() instead of the File constructor. E.g. saying
"File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
path if that's what was supplied, or would evaluate a partial path relative to the CWD.
*/
bassertfalse;
}
#endif
return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
}
#endif
while (path.endsWithChar (separator) && path != separatorString) // careful not to turn a single "/" into an empty string.
path = path.dropLastCharacters (1);
return path;
}
String File::addTrailingSeparator (const String& path)
{
return path.endsWithChar (separator) ? path
: path + separator;
}
//==============================================================================
#if BEAST_LINUX
#define NAMES_ARE_CASE_SENSITIVE 1
#endif
bool File::areFileNamesCaseSensitive()
{
#if NAMES_ARE_CASE_SENSITIVE
return true;
#else
return false;
#endif
}
static int compareFilenames (const String& name1, const String& name2) noexcept
{
#if NAMES_ARE_CASE_SENSITIVE
return name1.compare (name2);
#else
return name1.compareIgnoreCase (name2);
#endif
}
bool File::operator== (const File& other) const { return compareFilenames (fullPath, other.fullPath) == 0; }
bool File::operator!= (const File& other) const { return compareFilenames (fullPath, other.fullPath) != 0; }
bool File::operator< (const File& other) const { return compareFilenames (fullPath, other.fullPath) < 0; }
bool File::operator> (const File& other) const { return compareFilenames (fullPath, other.fullPath) > 0; }
//==============================================================================
bool File::deleteRecursively() const
{
bool worked = true;
if (isDirectory())
{
Array<File> subFiles;
findChildFiles (subFiles, File::findFilesAndDirectories, false);
for (int i = subFiles.size(); --i >= 0;)
worked = subFiles.getReference(i).deleteRecursively() && worked;
}
return deleteFile() && worked;
}
//==============================================================================
String File::getPathUpToLastSlash() const
{
const int lastSlash = fullPath.lastIndexOfChar (separator);
if (lastSlash > 0)
return fullPath.substring (0, lastSlash);
if (lastSlash == 0)
return separatorString;
return fullPath;
}
File File::getParentDirectory() const
{
File f;
f.fullPath = getPathUpToLastSlash();
return f;
}
//==============================================================================
String File::getFileName() const
{
return fullPath.substring (fullPath.lastIndexOfChar (separator) + 1);
}
String File::getFileNameWithoutExtension() const
{
const int lastSlash = fullPath.lastIndexOfChar (separator) + 1;
const int lastDot = fullPath.lastIndexOfChar ('.');
if (lastDot > lastSlash)
return fullPath.substring (lastSlash, lastDot);
return fullPath.substring (lastSlash);
}
bool File::isAChildOf (const File& potentialParent) const
{
if (potentialParent == File::nonexistent ())
return false;
const String ourPath (getPathUpToLastSlash());
if (compareFilenames (potentialParent.fullPath, ourPath) == 0)
return true;
if (potentialParent.fullPath.length() >= ourPath.length())
return false;
return getParentDirectory().isAChildOf (potentialParent);
}
//==============================================================================
bool File::isAbsolutePath (const String& path)
{
return path.startsWithChar (separator)
#if BEAST_WINDOWS
|| (path.isNotEmpty() && path[1] == ':');
#else
|| path.startsWithChar ('~');
#endif
}
File File::getChildFile (String relativePath) const
{
if (isAbsolutePath (relativePath))
return File (relativePath);
String path (fullPath);
// It's relative, so remove any ../ or ./ bits at the start..
if (relativePath[0] == '.')
{
#if BEAST_WINDOWS
relativePath = relativePath.replaceCharacter ('/', '\\');
#endif
while (relativePath[0] == '.')
{
const beast_wchar secondChar = relativePath[1];
if (secondChar == '.')
{
const beast_wchar thirdChar = relativePath[2];
if (thirdChar == 0 || thirdChar == separator)
{
const int lastSlash = path.lastIndexOfChar (separator);
if (lastSlash >= 0)
path = path.substring (0, lastSlash);
relativePath = relativePath.substring (3);
}
else
{
break;
}
}
else if (secondChar == separator)
{
relativePath = relativePath.substring (2);
}
else
{
break;
}
}
}
return File (addTrailingSeparator (path) + relativePath);
}
File File::getSiblingFile (const String& fileName) const
{
return getParentDirectory().getChildFile (fileName);
}
//==============================================================================
Result File::create() const
{
if (exists())
return Result::ok();
const File parentDir (getParentDirectory());
if (parentDir == *this)
return Result::fail ("Cannot create parent directory");
Result r (parentDir.createDirectory());
if (r.wasOk())
{
FileOutputStream fo (*this, 8);
r = fo.getStatus();
}
return r;
}
Result File::createDirectory() const
{
if (isDirectory())
return Result::ok();
const File parentDir (getParentDirectory());
if (parentDir == *this)
return Result::fail ("Cannot create parent directory");
Result r (parentDir.createDirectory());
if (r.wasOk())
r = createDirectoryInternal (fullPath.trimCharactersAtEnd (separatorString));
return r;
}
//==============================================================================
int File::findChildFiles (Array<File>& results,
const int whatToLookFor,
const bool searchRecursively,
const String& wildCardPattern) const
{
DirectoryIterator di (*this, searchRecursively, wildCardPattern, whatToLookFor);
int total = 0;
while (di.next())
{
results.add (di.getFile());
++total;
}
return total;
}
int File::getNumberOfChildFiles (const int whatToLookFor, const String& wildCardPattern) const
{
DirectoryIterator di (*this, false, wildCardPattern, whatToLookFor);
int total = 0;
while (di.next())
++total;
return total;
}
//==============================================================================
String File::getFileExtension() const
{
const int indexOfDot = fullPath.lastIndexOfChar ('.');
if (indexOfDot > fullPath.lastIndexOfChar (separator))
return fullPath.substring (indexOfDot);
return String::empty;
}
bool File::hasFileExtension (const String& possibleSuffix) const
{
if (possibleSuffix.isEmpty())
return fullPath.lastIndexOfChar ('.') <= fullPath.lastIndexOfChar (separator);
const int semicolon = possibleSuffix.indexOfChar (0, ';');
if (semicolon >= 0)
{
return hasFileExtension (possibleSuffix.substring (0, semicolon).trimEnd())
|| hasFileExtension (possibleSuffix.substring (semicolon + 1).trimStart());
}
else
{
if (fullPath.endsWithIgnoreCase (possibleSuffix))
{
if (possibleSuffix.startsWithChar ('.'))
return true;
const int dotPos = fullPath.length() - possibleSuffix.length() - 1;
if (dotPos >= 0)
return fullPath [dotPos] == '.';
}
}
return false;
}
File File::withFileExtension (const String& newExtension) const
{
if (fullPath.isEmpty())
return File::nonexistent ();
String filePart (getFileName());
const int i = filePart.lastIndexOfChar ('.');
if (i >= 0)
filePart = filePart.substring (0, i);
if (newExtension.isNotEmpty() && ! newExtension.startsWithChar ('.'))
filePart << '.';
return getSiblingFile (filePart + newExtension);
}
//==============================================================================
FileInputStream* File::createInputStream() const
{
std::unique_ptr <FileInputStream> fin (new FileInputStream (*this));
if (fin->openedOk())
return fin.release();
return nullptr;
}
FileOutputStream* File::createOutputStream (const size_t bufferSize) const
{
std::unique_ptr <FileOutputStream> out (new FileOutputStream (*this, bufferSize));
return out->failedToOpen() ? nullptr
: out.release();
}
//==============================================================================
bool File::appendData (const void* const dataToAppend,
const size_t numberOfBytes) const
{
bassert (((std::ptrdiff_t) numberOfBytes) >= 0);
if (numberOfBytes == 0)
return true;
FileOutputStream out (*this, 8192);
return out.openedOk() && out.write (dataToAppend, numberOfBytes);
}
bool File::appendText (const String& text,
const bool asUnicode,
const bool writeUnicodeHeaderBytes) const
{
FileOutputStream out (*this);
if (out.failedToOpen())
return false;
out.writeText (text, asUnicode, writeUnicodeHeaderBytes);
return true;
}
//==============================================================================
File File::createTempFile (const String& fileNameEnding)
{
const File tempFile (getSpecialLocation (tempDirectory)
.getChildFile ("temp_" + String::toHexString (Random::getSystemRandom().nextInt()))
.withFileExtension (fileNameEnding));
if (tempFile.exists())
return createTempFile (fileNameEnding);
return tempFile;
}
} // beast

View File

@@ -1,529 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_CORE_FILES_FILE_H_INCLUDED
#define BEAST_MODULE_CORE_FILES_FILE_H_INCLUDED
#include <beast/module/core/containers/Array.h>
#include <beast/module/core/memory/MemoryBlock.h>
#include <beast/module/core/misc/Result.h>
#include <beast/module/core/text/StringArray.h>
#include <beast/module/core/threads/CriticalSection.h>
namespace beast {
class FileInputStream;
class FileOutputStream;
//==============================================================================
/**
Represents a local file or directory.
This class encapsulates the absolute pathname of a file or directory, and
has methods for finding out about the file and changing its properties.
To read or write to the file, there are methods for returning an input or
output stream.
@see FileInputStream, FileOutputStream
*/
class File
{
public:
//==============================================================================
/** Creates an (invalid) file object.
The file is initially set to an empty path, so getFullPath() will return
an empty string, and comparing the file to File::nonexistent will return
true.
You can use its operator= method to point it at a proper file.
*/
File() noexcept {}
/** Creates a file from an absolute path.
If the path supplied is a relative path, it is taken to be relative
to the current working directory (see File::getCurrentWorkingDirectory()),
but this isn't a recommended way of creating a file, because you
never know what the CWD is going to be.
On the Mac/Linux, the path can include "~" notation for referring to
user home directories.
*/
File (const String& absolutePath);
/** Creates a copy of another file object. */
File (const File&);
/** Destructor. */
~File() noexcept {}
/** Sets the file based on an absolute pathname.
If the path supplied is a relative path, it is taken to be relative
to the current working directory (see File::getCurrentWorkingDirectory()),
but this isn't a recommended way of creating a file, because you
never know what the CWD is going to be.
On the Mac/Linux, the path can include "~" notation for referring to
user home directories.
*/
File& operator= (const String& newAbsolutePath);
/** Copies from another file object. */
File& operator= (const File& otherFile);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
File (File&&) noexcept;
File& operator= (File&&) noexcept;
#endif
//==============================================================================
/** This static constant is used for referring to an 'invalid' file. */
static File const& nonexistent ();
//==============================================================================
/** Checks whether the file actually exists.
@returns true if the file exists, either as a file or a directory.
@see existsAsFile, isDirectory
*/
bool exists() const;
/** Checks whether the file exists and is a file rather than a directory.
@returns true only if this is a real file, false if it's a directory
or doesn't exist
@see exists, isDirectory
*/
bool existsAsFile() const;
/** Checks whether the file is a directory that exists.
@returns true only if the file is a directory which actually exists, so
false if it's a file or doesn't exist at all
@see exists, existsAsFile
*/
bool isDirectory() const;
/** Returns the size of the file in bytes.
@returns the number of bytes in the file, or 0 if it doesn't exist.
*/
std::int64_t getSize() const;
//==============================================================================
/** Returns the complete, absolute path of this file.
This includes the filename and all its parent folders. On Windows it'll
also include the drive letter prefix; on Mac or Linux it'll be a complete
path starting from the root folder.
If you just want the file's name, you should use getFileName() or
getFileNameWithoutExtension().
@see getFileName
*/
const String& getFullPathName() const noexcept { return fullPath; }
/** Returns the last section of the pathname.
Returns just the final part of the path - e.g. if the whole path
is "/moose/fish/foo.txt" this will return "foo.txt".
For a directory, it returns the final part of the path - e.g. for the
directory "/moose/fish" it'll return "fish".
If the filename begins with a dot, it'll return the whole filename, e.g. for
"/moose/.fish", it'll return ".fish"
@see getFullPathName, getFileNameWithoutExtension
*/
String getFileName() const;
//==============================================================================
/** Returns the file's extension.
Returns the file extension of this file, also including the dot.
e.g. "/moose/fish/foo.txt" would return ".txt"
@see hasFileExtension, withFileExtension, getFileNameWithoutExtension
*/
String getFileExtension() const;
/** Checks whether the file has a given extension.
@param extensionToTest the extension to look for - it doesn't matter whether or
not this string has a dot at the start, so ".wav" and "wav"
will have the same effect. To compare with multiple extensions, this
parameter can contain multiple strings, separated by semi-colons -
so, for example: hasFileExtension (".jpeg;png;gif") would return
true if the file has any of those three extensions.
@see getFileExtension, withFileExtension, getFileNameWithoutExtension
*/
bool hasFileExtension (const String& extensionToTest) const;
/** Returns a version of this file with a different file extension.
e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html"
@param newExtension the new extension, either with or without a dot at the start (this
doesn't make any difference). To get remove a file's extension altogether,
pass an empty string into this function.
@see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension
*/
File withFileExtension (const String& newExtension) const;
/** Returns the last part of the filename, without its file extension.
e.g. for "/moose/fish/foo.txt" this will return "foo".
@see getFileName, getFileExtension, hasFileExtension, withFileExtension
*/
String getFileNameWithoutExtension() const;
//==============================================================================
/** Returns a file that represents a relative (or absolute) sub-path of the current one.
This will find a child file or directory of the current object.
e.g.
File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt".
File ("/moose/fish").getChildFile ("haddock/foo.txt") will produce "/moose/fish/haddock/foo.txt".
File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt".
If the string is actually an absolute path, it will be treated as such, e.g.
File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt"
@see getSiblingFile, getParentDirectory, isAChildOf
*/
File getChildFile (String relativeOrAbsolutePath) const;
/** Returns a file which is in the same directory as this one.
This is equivalent to getParentDirectory().getChildFile (name).
@see getChildFile, getParentDirectory
*/
File getSiblingFile (const String& siblingFileName) const;
//==============================================================================
/** Returns the directory that contains this file or directory.
e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
*/
File getParentDirectory() const;
/** Checks whether a file is somewhere inside a directory.
Returns true if this file is somewhere inside a subdirectory of the directory
that is passed in. Neither file actually has to exist, because the function
just checks the paths for similarities.
e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true.
File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true.
*/
bool isAChildOf (const File& potentialParentDirectory) const;
//==============================================================================
/** Compares the pathnames for two files. */
bool operator== (const File&) const;
/** Compares the pathnames for two files. */
bool operator!= (const File&) const;
/** Compares the pathnames for two files. */
bool operator< (const File&) const;
/** Compares the pathnames for two files. */
bool operator> (const File&) const;
//==============================================================================
/** Creates an empty file if it doesn't already exist.
If the file that this object refers to doesn't exist, this will create a file
of zero size.
If it already exists or is a directory, this method will do nothing.
@returns true if the file has been created (or if it already existed).
@see createDirectory
*/
Result create() const;
/** Creates a new directory for this filename.
This will try to create the file as a directory, and fill also create
any parent directories it needs in order to complete the operation.
@returns a result to indicate whether the directory was created successfully, or
an error message if it failed.
@see create
*/
Result createDirectory() const;
/** Deletes a file.
If this file is actually a directory, it may not be deleted correctly if it
contains files. See deleteRecursively() as a better way of deleting directories.
@returns true if the file has been successfully deleted (or if it didn't exist to
begin with).
@see deleteRecursively
*/
bool deleteFile() const;
/** Deletes a file or directory and all its subdirectories.
If this file is a directory, this will try to delete it and all its subfolders. If
it's just a file, it will just try to delete the file.
@returns true if the file and all its subfolders have been successfully deleted
(or if it didn't exist to begin with).
@see deleteFile
*/
bool deleteRecursively() const;
//==============================================================================
/** Used in file searching, to specify whether to return files, directories, or both.
*/
enum TypesOfFileToFind
{
findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */
findFiles = 2, /**< Use this flag to indicate that you want to find files. */
findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */
ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */
};
/** Searches inside a directory for files matching a wildcard pattern.
Assuming that this file is a directory, this method will search it
for either files or subdirectories whose names match a filename pattern.
@param results an array to which File objects will be added for the
files that the search comes up with
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
return files, directories, or both. If the ignoreHiddenFiles flag
is also added to this value, hidden files won't be returned
@param searchRecursively if true, all subdirectories will be recursed into to do
an exhaustive search
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
@returns the number of results that have been found
@see getNumberOfChildFiles, DirectoryIterator
*/
int findChildFiles (Array<File>& results,
int whatToLookFor,
bool searchRecursively,
const String& wildCardPattern = "*") const;
/** Searches inside a directory and counts how many files match a wildcard pattern.
Assuming that this file is a directory, this method will search it
for either files or subdirectories whose names match a filename pattern,
and will return the number of matches found.
This isn't a recursive call, and will only search this directory, not
its children.
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
count files, directories, or both. If the ignoreHiddenFiles flag
is also added to this value, hidden files won't be counted
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
@returns the number of matches found
@see findChildFiles, DirectoryIterator
*/
int getNumberOfChildFiles (int whatToLookFor,
const String& wildCardPattern = "*") const;
//==============================================================================
/** Creates a stream to read from this file.
@returns a stream that will read from this file (initially positioned at the
start of the file), or nullptr if the file can't be opened for some reason
@see createOutputStream
*/
FileInputStream* createInputStream() const;
/** Creates a stream to write to this file.
If the file exists, the stream that is returned will be positioned ready for
writing at the end of the file, so you might want to use deleteFile() first
to write to an empty file.
@returns a stream that will write to this file (initially positioned at the
end of the file), or nullptr if the file can't be opened for some reason
@see createInputStream, appendData, appendText
*/
FileOutputStream* createOutputStream (size_t bufferSize = 0x8000) const;
//==============================================================================
/** Appends a block of binary data to the end of the file.
This will try to write the given buffer to the end of the file.
@returns false if it can't write to the file for some reason
*/
bool appendData (const void* dataToAppend,
size_t numberOfBytes) const;
/** Appends a string to the end of the file.
This will try to append a text string to the file, as either 16-bit unicode
or 8-bit characters in the default system encoding.
It can also write the 'ff fe' unicode header bytes before the text to indicate
the endianness of the file.
Any single \\n characters in the string are replaced with \\r\\n before it is written.
@see replaceWithText
*/
bool appendText (const String& textToAppend,
bool asUnicode = false,
bool writeUnicodeHeaderBytes = false) const;
//==============================================================================
/** A set of types of location that can be passed to the getSpecialLocation() method.
*/
enum SpecialLocationType
{
/** The user's home folder. This is the same as using File ("~"). */
userHomeDirectory,
/** The user's default documents folder. On Windows, this might be the user's
"My Documents" folder. On the Mac it'll be their "Documents" folder. Linux
doesn't tend to have one of these, so it might just return their home folder.
*/
userDocumentsDirectory,
/** The folder that contains the user's desktop objects. */
userDesktopDirectory,
/** The most likely place where a user might store their music files. */
userMusicDirectory,
/** The most likely place where a user might store their movie files. */
userMoviesDirectory,
/** The most likely place where a user might store their picture files. */
userPicturesDirectory,
/** The folder in which applications store their persistent user-specific settings.
On Windows, this might be "\Documents and Settings\username\Application Data".
On the Mac, it might be "~/Library". If you're going to store your settings in here,
always create your own sub-folder to put them in, to avoid making a mess.
*/
userApplicationDataDirectory,
/** An equivalent of the userApplicationDataDirectory folder that is shared by all users
of the computer, rather than just the current user.
On the Mac it'll be "/Library", on Windows, it could be something like
"\Documents and Settings\All Users\Application Data".
Depending on the setup, this folder may be read-only.
*/
commonApplicationDataDirectory,
/** A place to put documents which are shared by all users of the machine.
On Windows this may be somewhere like "C:\Users\Public\Documents", on OSX it
will be something like "/Users/Shared". Other OSes may have no such concept
though, so be careful.
*/
commonDocumentsDirectory,
/** The folder that should be used for temporary files.
Always delete them when you're finished, to keep the user's computer tidy!
*/
tempDirectory,
/** The directory in which applications normally get installed.
So on windows, this would be something like "c:\program files", on the
Mac "/Applications", or "/usr" on linux.
*/
globalApplicationsDirectory
};
/** Finds the location of a special type of file or directory, such as a home folder or
documents folder.
@see SpecialLocationType
*/
static File getSpecialLocation (const SpecialLocationType type);
//==============================================================================
/** Returns a temporary file in the system's temp directory.
This will try to return the name of a non-existent temp file.
To get the temp folder, you can use getSpecialLocation (File::tempDirectory).
*/
static File createTempFile (const String& fileNameEnding);
//==============================================================================
/** Returns the current working directory. */
static File getCurrentWorkingDirectory();
//==============================================================================
/** The system-specific file separator character.
On Windows, this will be '\', on Mac/Linux, it'll be '/'
*/
static const beast_wchar separator;
/** The system-specific file separator character, as a string.
On Windows, this will be '\', on Mac/Linux, it'll be '/'
*/
static const String separatorString;
//==============================================================================
/** Indicates whether filenames are case-sensitive on the current operating system. */
static bool areFileNamesCaseSensitive();
/** Returns true if the string seems to be a fully-specified absolute path. */
static bool isAbsolutePath (const String& path);
/** Creates a file that simply contains this string, without doing the sanity-checking
that the normal constructors do.
Best to avoid this unless you really know what you're doing.
*/
static File createFileWithoutCheckingPath (const String& absolutePath) noexcept;
/** Adds a separator character to the end of a path if it doesn't already have one. */
static String addTrailingSeparator (const String& path);
private:
//==============================================================================
String fullPath;
static String parseAbsolutePath (const String&);
String getPathUpToLastSlash() const;
Result createDirectoryInternal (const String&) const;
};
} // beast
#endif

View File

@@ -1,95 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
std::int64_t beast_fileSetPosition (void* handle, std::int64_t pos);
//==============================================================================
FileInputStream::FileInputStream (const File& f)
: file (f),
fileHandle (nullptr),
currentPosition (0),
status (Result::ok()),
needToSeek (true)
{
openHandle();
}
FileInputStream::~FileInputStream()
{
closeHandle();
}
//==============================================================================
std::int64_t FileInputStream::getTotalLength()
{
return file.getSize();
}
int FileInputStream::read (void* buffer, int bytesToRead)
{
bassert (openedOk());
bassert (buffer != nullptr && bytesToRead >= 0);
if (needToSeek)
{
if (beast_fileSetPosition (fileHandle, currentPosition) < 0)
return 0;
needToSeek = false;
}
const size_t num = readInternal (buffer, (size_t) bytesToRead);
currentPosition += num;
return (int) num;
}
bool FileInputStream::isExhausted()
{
return currentPosition >= getTotalLength();
}
std::int64_t FileInputStream::getPosition()
{
return currentPosition;
}
bool FileInputStream::setPosition (std::int64_t pos)
{
bassert (openedOk());
if (pos != currentPosition)
{
pos = blimit ((std::int64_t) 0, getTotalLength(), pos);
needToSeek |= (currentPosition != pos);
currentPosition = pos;
}
return true;
}
} // beast

View File

@@ -1,94 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_CORE_FILES_FILEINPUTSTREAM_H_INCLUDED
#define BEAST_MODULE_CORE_FILES_FILEINPUTSTREAM_H_INCLUDED
namespace beast
{
//==============================================================================
/**
An input stream that reads from a local file.
@see InputStream, FileOutputStream, File::createInputStream
*/
class FileInputStream
: public InputStream
{
public:
//==============================================================================
/** Creates a FileInputStream.
@param fileToRead the file to read from - if the file can't be accessed for some
reason, then the stream will just contain no data
*/
explicit FileInputStream (const File& fileToRead);
/** Destructor. */
~FileInputStream();
//==============================================================================
/** Returns the file that this stream is reading from. */
const File& getFile() const noexcept { return file; }
/** Returns the status of the file stream.
The result will be ok if the file opened successfully. If an error occurs while
opening or reading from the file, this will contain an error message.
*/
const Result& getStatus() const noexcept { return status; }
/** Returns true if the stream couldn't be opened for some reason.
@see getResult()
*/
bool failedToOpen() const noexcept { return status.failed(); }
/** Returns true if the stream opened without problems.
@see getResult()
*/
bool openedOk() const noexcept { return status.wasOk(); }
//==============================================================================
std::int64_t getTotalLength();
int read (void* destBuffer, int maxBytesToRead);
bool isExhausted();
std::int64_t getPosition();
bool setPosition (std::int64_t pos);
private:
//==============================================================================
File file;
void* fileHandle;
std::int64_t currentPosition;
Result status;
bool needToSeek;
void openHandle();
void closeHandle();
size_t readInternal (void* buffer, size_t numBytes);
};
} // beast
#endif // BEAST_FILEINPUTSTREAM_H_INCLUDED

View File

@@ -1,137 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <algorithm>
namespace beast
{
std::int64_t beast_fileSetPosition (void* handle, std::int64_t pos);
//==============================================================================
FileOutputStream::FileOutputStream (const File& f, const size_t bufferSizeToUse)
: file (f),
fileHandle (nullptr),
status (Result::ok()),
currentPosition (0),
bufferSize (bufferSizeToUse),
bytesInBuffer (0),
buffer (std::max (bufferSizeToUse, (size_t) 16))
{
openHandle();
}
FileOutputStream::~FileOutputStream()
{
flushBuffer();
flushInternal();
closeHandle();
}
std::int64_t FileOutputStream::getPosition()
{
return currentPosition;
}
bool FileOutputStream::setPosition (std::int64_t newPosition)
{
if (newPosition != currentPosition)
{
flushBuffer();
currentPosition = beast_fileSetPosition (fileHandle, newPosition);
}
return newPosition == currentPosition;
}
bool FileOutputStream::flushBuffer()
{
bool ok = true;
if (bytesInBuffer > 0)
{
ok = (writeInternal (buffer, bytesInBuffer) == (std::ptrdiff_t) bytesInBuffer);
bytesInBuffer = 0;
}
return ok;
}
void FileOutputStream::flush()
{
flushBuffer();
flushInternal();
}
bool FileOutputStream::write (const void* const src, const size_t numBytes)
{
bassert (src != nullptr && ((std::ptrdiff_t) numBytes) >= 0);
if (bytesInBuffer + numBytes < bufferSize)
{
memcpy (buffer + bytesInBuffer, src, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
}
else
{
if (! flushBuffer())
return false;
if (numBytes < bufferSize)
{
memcpy (buffer + bytesInBuffer, src, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
}
else
{
const std::ptrdiff_t bytesWritten = writeInternal (src, numBytes);
if (bytesWritten < 0)
return false;
currentPosition += bytesWritten;
return bytesWritten == (std::ptrdiff_t) numBytes;
}
}
return true;
}
bool FileOutputStream::writeRepeatedByte (std::uint8_t byte, size_t numBytes)
{
bassert (((std::ptrdiff_t) numBytes) >= 0);
if (bytesInBuffer + numBytes < bufferSize)
{
memset (buffer + bytesInBuffer, byte, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
return true;
}
return OutputStream::writeRepeatedByte (byte, numBytes);
}
} // beast

View File

@@ -1,112 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
#ifndef BEAST_MODULE_CORE_FILES_FILEOUTPUTSTREAM_H_INCLUDED
#define BEAST_MODULE_CORE_FILES_FILEOUTPUTSTREAM_H_INCLUDED
//==============================================================================
/**
An output stream that writes into a local file.
@see OutputStream, FileInputStream, File::createOutputStream
*/
class FileOutputStream
: public OutputStream
{
public:
//==============================================================================
/** Creates a FileOutputStream.
If the file doesn't exist, it will first be created. If the file can't be
created or opened, the failedToOpen() method will return
true.
If the file already exists when opened, the stream's write-postion will
be set to the end of the file. To overwrite an existing file,
use File::deleteFile() before opening the stream, or use setPosition(0)
after it's opened (although this won't truncate the file).
*/
FileOutputStream (const File& fileToWriteTo,
size_t bufferSizeToUse = 16384);
/** Destructor. */
~FileOutputStream();
//==============================================================================
/** Returns the file that this stream is writing to.
*/
const File& getFile() const { return file; }
/** Returns the status of the file stream.
The result will be ok if the file opened successfully. If an error occurs while
opening or writing to the file, this will contain an error message.
*/
const Result& getStatus() const noexcept { return status; }
/** Returns true if the stream couldn't be opened for some reason.
@see getResult()
*/
bool failedToOpen() const noexcept { return status.failed(); }
/** Returns true if the stream opened without problems.
@see getResult()
*/
bool openedOk() const noexcept { return status.wasOk(); }
/** Attempts to truncate the file to the current write position.
To truncate a file to a specific size, first use setPosition() to seek to the
appropriate location, and then call this method.
*/
Result truncate();
//==============================================================================
void flush() override;
std::int64_t getPosition() override;
bool setPosition (std::int64_t) override;
bool write (const void*, size_t) override;
bool writeRepeatedByte (std::uint8_t byte, size_t numTimesToRepeat) override;
private:
//==============================================================================
File file;
void* fileHandle;
Result status;
std::int64_t currentPosition;
size_t bufferSize, bytesInBuffer;
HeapBlock <char> buffer;
void openHandle();
void closeHandle();
void flushInternal();
bool flushBuffer();
std::int64_t setPositionInternal (std::int64_t);
std::ptrdiff_t writeInternal (const void*, size_t);
};
} // beast
#endif

View File

@@ -24,8 +24,6 @@
#ifndef BEAST_MODULE_CORE_LOGGING_LOGGER_H_INCLUDED #ifndef BEAST_MODULE_CORE_LOGGING_LOGGER_H_INCLUDED
#define BEAST_MODULE_CORE_LOGGING_LOGGER_H_INCLUDED #define BEAST_MODULE_CORE_LOGGING_LOGGER_H_INCLUDED
#include <beast/strings/String.h>
namespace beast namespace beast
{ {

View File

@@ -1,152 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
Random::Random (const std::int64_t seedValue) noexcept
: seed (seedValue)
{
nextInt (); // fixes a bug where the first int is always 0
}
Random::Random()
: seed (1)
{
setSeedRandomly();
}
Random::~Random() noexcept
{
}
void Random::setSeed (const std::int64_t newSeed) noexcept
{
seed = newSeed;
nextInt (); // fixes a bug where the first int is always 0
}
void Random::combineSeed (const std::int64_t seedValue) noexcept
{
seed ^= nextInt64() ^ seedValue;
}
void Random::setSeedRandomly()
{
static std::int64_t globalSeed = 0;
combineSeed (globalSeed ^ (std::int64_t) (std::intptr_t) this);
combineSeed (Time::currentTimeMillis());
globalSeed ^= seed;
nextInt (); // fixes a bug where the first int is always 0
}
Random& Random::getSystemRandom() noexcept
{
static Random sysRand;
return sysRand;
}
//==============================================================================
int Random::nextInt() noexcept
{
seed = (seed * 0x5deece66dLL + 11) & 0xffffffffffffULL;
return (int) (seed >> 16);
}
int Random::nextInt (const int maxValue) noexcept
{
bassert (maxValue > 0);
return (int) ((((unsigned int) nextInt()) * (std::uint64_t) maxValue) >> 32);
}
std::int64_t Random::nextInt64() noexcept
{
return (((std::int64_t) nextInt()) << 32) | (std::int64_t) (std::uint64_t) (std::uint32_t) nextInt();
}
bool Random::nextBool() noexcept
{
return (nextInt() & 0x40000000) != 0;
}
float Random::nextFloat() noexcept
{
return static_cast <std::uint32_t> (nextInt()) / (float) 0xffffffff;
}
double Random::nextDouble() noexcept
{
return static_cast <std::uint32_t> (nextInt()) / (double) 0xffffffff;
}
void Random::fillBitsRandomly (void* const buffer, size_t bytes)
{
int* d = static_cast<int*> (buffer);
for (; bytes >= sizeof (int); bytes -= sizeof (int))
*d++ = nextInt();
if (bytes > 0)
{
const int lastBytes = nextInt();
memcpy (d, &lastBytes, bytes);
}
}
//==============================================================================
class Random_test : public unit_test::suite
{
public:
void run()
{
for (int j = 10; --j >= 0;)
{
Random r;
r.setSeedRandomly();
for (int i = 20; --i >= 0;)
{
expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0);
expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f);
expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5);
expect (r.nextInt (1) == 0);
int n = r.nextInt (50) + 1;
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
n = r.nextInt (0x7ffffffe) + 1;
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
}
}
}
};
BEAST_DEFINE_TESTSUITE(Random,beast_core,beast);
} // beast

View File

@@ -1,130 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_CORE_MATHS_RANDOM_H_INCLUDED
#define BEAST_MODULE_CORE_MATHS_RANDOM_H_INCLUDED
#include <cstddef>
#include <cstdint>
namespace beast {
//==============================================================================
/**
A random number generator.
You can create a Random object and use it to generate a sequence of random numbers.
*/
class Random
{
public:
//==============================================================================
/** Creates a Random object based on a seed value.
For a given seed value, the subsequent numbers generated by this object
will be predictable, so a good idea is to set this value based
on the time, e.g.
new Random (Time::currentTimeMillis())
*/
explicit Random (std::int64_t seedValue) noexcept;
/** Creates a Random object using a random seed value.
Internally, this calls setSeedRandomly() to randomise the seed.
*/
Random();
/** Destructor. */
~Random() noexcept;
/** Returns the next random 32 bit integer.
@returns a random integer from the full range 0x80000000 to 0x7fffffff
*/
int nextInt() noexcept;
/** Returns the next random number, limited to a given range.
The maxValue parameter may not be negative, or zero.
@returns a random integer between 0 (inclusive) and maxValue (exclusive).
*/
int nextInt (int maxValue) noexcept;
/** Returns the next 64-bit random number.
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
*/
std::int64_t nextInt64() noexcept;
/** Returns the next random floating-point number.
@returns a random value in the range 0 to 1.0
*/
float nextFloat() noexcept;
/** Returns the next random floating-point number.
@returns a random value in the range 0 to 1.0
*/
double nextDouble() noexcept;
/** Returns the next random boolean value.
*/
bool nextBool() noexcept;
/** Fills a block of memory with random values. */
void fillBitsRandomly (void* bufferToFill, size_t sizeInBytes);
//==============================================================================
/** Resets this Random object to a given seed value. */
void setSeed (std::int64_t newSeed) noexcept;
/** Merges this object's seed with another value.
This sets the seed to be a value created by combining the current seed and this
new value.
*/
void combineSeed (std::int64_t seedValue) noexcept;
/** Reseeds this generator using a value generated from various semi-random system
properties like the current time, etc.
Because this function convolves the time with the last seed value, calling
it repeatedly will increase the randomness of the final result.
*/
void setSeedRandomly();
/** The overhead of creating a new Random object is fairly small, but if you want to avoid
it, you can call this method to get a global shared Random object.
It's not thread-safe though, so threads should use their own Random object, otherwise
you run the risk of your random numbers becoming.. erm.. randomly corrupted..
*/
static Random& getSystemRandom() noexcept;
private:
//==============================================================================
std::int64_t seed;
};
} // beast
#endif // BEAST_RANDOM_H_INCLUDED

View File

@@ -1,412 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <algorithm>
namespace beast
{
MemoryBlock::MemoryBlock() noexcept
: size (0)
{
}
MemoryBlock::MemoryBlock (const size_t initialSize, const bool initialiseToZero)
{
if (initialSize > 0)
{
size = initialSize;
data.allocate (initialSize, initialiseToZero);
}
else
{
size = 0;
}
}
MemoryBlock::MemoryBlock (const MemoryBlock& other)
: size (other.size)
{
if (size > 0)
{
bassert (other.data != nullptr);
data.malloc (size);
memcpy (data, other.data, size);
}
}
MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
: size (sizeInBytes)
{
bassert (((std::ptrdiff_t) sizeInBytes) >= 0);
if (size > 0)
{
bassert (dataToInitialiseFrom != nullptr); // non-zero size, but a zero pointer passed-in?
data.malloc (size);
if (dataToInitialiseFrom != nullptr)
memcpy (data, dataToInitialiseFrom, size);
}
}
MemoryBlock::~MemoryBlock() noexcept
{
}
MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
{
if (this != &other)
{
setSize (other.size, false);
memcpy (data, other.data, size);
}
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
: data (static_cast <HeapBlock <char>&&> (other.data)),
size (other.size)
{
}
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
{
data = static_cast <HeapBlock <char>&&> (other.data);
size = other.size;
return *this;
}
#endif
//==============================================================================
bool MemoryBlock::operator== (const MemoryBlock& other) const noexcept
{
return matches (other.data, other.size);
}
bool MemoryBlock::operator!= (const MemoryBlock& other) const noexcept
{
return ! operator== (other);
}
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const noexcept
{
return size == dataSize
&& memcmp (data, dataToCompare, size) == 0;
}
//==============================================================================
// this will resize the block to this size
void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
{
if (size != newSize)
{
if (newSize <= 0)
{
data.free_up();
size = 0;
}
else
{
if (data != nullptr)
{
data.reallocate (newSize);
if (initialiseToZero && (newSize > size))
zeromem (data + size, newSize - size);
}
else
{
data.allocate (newSize, initialiseToZero);
}
size = newSize;
}
}
}
void MemoryBlock::ensureSize (const size_t minimumSize, const bool initialiseToZero)
{
if (size < minimumSize)
setSize (minimumSize, initialiseToZero);
}
void MemoryBlock::swapWith (MemoryBlock& other) noexcept
{
std::swap (size, other.size);
data.swapWith (other.data);
}
//==============================================================================
void MemoryBlock::fillWith (const std::uint8_t value) noexcept
{
memset (data, (int) value, size);
}
void MemoryBlock::append (const void* const srcData, const size_t numBytes)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
const size_t oldSize = size;
setSize (size + numBytes);
memcpy (data + oldSize, srcData, numBytes);
}
}
void MemoryBlock::replaceWith (const void* const srcData, const size_t numBytes)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
setSize (numBytes);
memcpy (data, srcData, numBytes);
}
}
void MemoryBlock::insert (const void* const srcData, const size_t numBytes, size_t insertPosition)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
insertPosition = std::min (size, insertPosition);
const size_t trailingDataSize = size - insertPosition;
setSize (size + numBytes, false);
if (trailingDataSize > 0)
memmove (data + insertPosition + numBytes,
data + insertPosition,
trailingDataSize);
memcpy (data + insertPosition, srcData, numBytes);
}
}
void MemoryBlock::removeSection (const size_t startByte, const size_t numBytesToRemove)
{
if (startByte + numBytesToRemove >= size)
{
setSize (startByte);
}
else if (numBytesToRemove > 0)
{
memmove (data + startByte,
data + startByte + numBytesToRemove,
size - (startByte + numBytesToRemove));
setSize (size - numBytesToRemove);
}
}
void MemoryBlock::copyFrom (const void* const src, int offset, size_t num) noexcept
{
const char* d = static_cast<const char*> (src);
if (offset < 0)
{
d -= offset;
num += (size_t) -offset;
offset = 0;
}
if ((size_t) offset + num > size)
num = size - (size_t) offset;
if (num > 0)
memcpy (data + offset, d, num);
}
void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcept
{
char* d = static_cast<char*> (dst);
if (offset < 0)
{
zeromem (d, (size_t) -offset);
d -= offset;
num -= (size_t) -offset;
offset = 0;
}
if ((size_t) offset + num > size)
{
const size_t newNum = size - (size_t) offset;
zeromem (d + newNum, num - newNum);
num = newNum;
}
if (num > 0)
memcpy (d, data + offset, num);
}
String MemoryBlock::toString() const
{
return String (CharPointer_UTF8 (data), size);
}
//==============================================================================
int MemoryBlock::getBitRange (const size_t bitRangeStart, size_t numBits) const noexcept
{
int res = 0;
size_t byte = bitRangeStart >> 3;
size_t offsetInByte = bitRangeStart & 7;
size_t bitsSoFar = 0;
while (numBits > 0 && (size_t) byte < size)
{
const size_t bitsThisTime = std::min (numBits, 8 - offsetInByte);
const int mask = (0xff >> (8 - bitsThisTime)) << offsetInByte;
res |= (((data[byte] & mask) >> offsetInByte) << bitsSoFar);
bitsSoFar += bitsThisTime;
numBits -= bitsThisTime;
++byte;
offsetInByte = 0;
}
return res;
}
void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int bitsToSet) noexcept
{
size_t byte = bitRangeStart >> 3;
size_t offsetInByte = bitRangeStart & 7;
std::uint32_t mask = ~((((std::uint32_t) 0xffffffff) << (32 - numBits)) >> (32 - numBits));
while (numBits > 0 && (size_t) byte < size)
{
const size_t bitsThisTime = std::min (numBits, 8 - offsetInByte);
const std::uint32_t tempMask = (mask << offsetInByte) | ~((((std::uint32_t) 0xffffffff) >> offsetInByte) << offsetInByte);
const std::uint32_t tempBits = (std::uint32_t) bitsToSet << offsetInByte;
data[byte] = (char) (((std::uint32_t) data[byte] & tempMask) | tempBits);
++byte;
numBits -= bitsThisTime;
bitsToSet >>= bitsThisTime;
mask >>= bitsThisTime;
offsetInByte = 0;
}
}
//==============================================================================
void MemoryBlock::loadFromHexString (const String& hex)
{
ensureSize ((size_t) hex.length() >> 1);
char* dest = data;
String::CharPointerType t (hex.getCharPointer());
for (;;)
{
int byte = 0;
for (int loop = 2; --loop >= 0;)
{
byte <<= 4;
for (;;)
{
const beast_wchar c = t.getAndAdvance();
if (c >= '0' && c <= '9') { byte |= c - '0'; break; }
if (c >= 'a' && c <= 'z') { byte |= c - ('a' - 10); break; }
if (c >= 'A' && c <= 'Z') { byte |= c - ('A' - 10); break; }
if (c == 0)
{
setSize (static_cast <size_t> (dest - data));
return;
}
}
}
*dest++ = (char) byte;
}
}
//==============================================================================
static char const* const base64EncodingTable = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
String MemoryBlock::toBase64Encoding() const
{
const size_t numChars = ((size << 3) + 5) / 6;
String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
const int initialLen = destString.length();
destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) initialLen + 2 + numChars);
String::CharPointerType d (destString.getCharPointer());
d += initialLen;
d.write ('.');
for (size_t i = 0; i < numChars; ++i)
d.write ((beast_wchar) (std::uint8_t) base64EncodingTable [getBitRange (i * 6, 6)]);
d.writeNull();
return destString;
}
bool MemoryBlock::fromBase64Encoding (const String& s)
{
const int startPos = s.indexOfChar ('.') + 1;
if (startPos <= 0)
return false;
const int numBytesNeeded = s.substring (0, startPos - 1).getIntValue();
setSize ((size_t) numBytesNeeded, true);
const int numChars = s.length() - startPos;
String::CharPointerType srcChars (s.getCharPointer());
srcChars += startPos;
int pos = 0;
for (int i = 0; i < numChars; ++i)
{
const char c = (char) srcChars.getAndAdvance();
for (int j = 0; j < 64; ++j)
{
if (base64EncodingTable[j] == c)
{
setBitRange ((size_t) pos, 6, j);
pos += 6;
break;
}
}
}
return true;
}
} // beast

View File

@@ -1,275 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_CORE_MEMORY_MEMORYBLOCK_H_INCLUDED
#define BEAST_MODULE_CORE_MEMORY_MEMORYBLOCK_H_INCLUDED
#include <beast/HeapBlock.h>
#include <beast/strings/String.h>
namespace beast {
//==============================================================================
/**
A class to hold a resizable block of raw data.
*/
class MemoryBlock
{
public:
//==============================================================================
/** Create an uninitialised block with 0 size. */
MemoryBlock() noexcept;
/** Creates a memory block with a given initial size.
@param initialSize the size of block to create
@param initialiseToZero whether to clear the memory or just leave it uninitialised
*/
MemoryBlock (const size_t initialSize,
bool initialiseToZero = false);
/** Creates a copy of another memory block. */
MemoryBlock (const MemoryBlock& other);
/** Creates a memory block using a copy of a block of data.
@param dataToInitialiseFrom some data to copy into this block
@param sizeInBytes how much space to use
*/
MemoryBlock (const void* dataToInitialiseFrom, size_t sizeInBytes);
/** Destructor. */
~MemoryBlock() noexcept;
/** Copies another memory block onto this one.
This block will be resized and copied to exactly match the other one.
*/
MemoryBlock& operator= (const MemoryBlock& other);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
MemoryBlock (MemoryBlock&& other) noexcept;
MemoryBlock& operator= (MemoryBlock&& other) noexcept;
#endif
// Standard container interface
using iterator = char*;
using const_iterator = char const*;
inline iterator begin () noexcept { return static_cast <iterator> (getData ()); }
inline iterator end () noexcept { return addBytesToPointer (begin (), size); }
inline const_iterator cbegin () const noexcept { return static_cast <const_iterator> (getConstData ()); }
inline const_iterator cend () const noexcept { return addBytesToPointer (cbegin (), size); }
//==============================================================================
/** Compares two memory blocks.
@returns true only if the two blocks are the same size and have identical contents.
*/
bool operator== (const MemoryBlock& other) const noexcept;
/** Compares two memory blocks.
@returns true if the two blocks are different sizes or have different contents.
*/
bool operator!= (const MemoryBlock& other) const noexcept;
/** Returns true if the data in this MemoryBlock matches the raw bytes passed-in.
*/
bool matches (const void* data, size_t dataSize) const noexcept;
//==============================================================================
/** Returns a void pointer to the data.
Note that the pointer returned will probably become invalid when the
block is resized.
*/
void* getData() const noexcept
{
return data;
}
/** Returns a void pointer to data as unmodifiable.
Note that the pointer returned will probably become invalid when the
block is resized.
*/
void const* getConstData() const noexcept
{
return data;
}
/** Returns a byte from the memory block.
This returns a reference, so you can also use it to set a byte.
*/
template <typename Type>
char& operator[] (const Type offset) const noexcept { return data [offset]; }
//==============================================================================
/** Returns the block's current allocated size, in bytes. */
size_t getSize() const noexcept { return size; }
/** Resizes the memory block.
This will try to keep as much of the block's current content as it can,
and can optionally be made to clear any new space that gets allocated at
the end of the block.
@param newSize the new desired size for the block
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
whether to clear the new section or just leave it
uninitialised
@see ensureSize
*/
void setSize (const size_t newSize,
bool initialiseNewSpaceToZero = false);
/** Increases the block's size only if it's smaller than a given size.
@param minimumSize if the block is already bigger than this size, no action
will be taken; otherwise it will be increased to this size
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
whether to clear the new section or just leave it
uninitialised
@see setSize
*/
void ensureSize (const size_t minimumSize,
bool initialiseNewSpaceToZero = false);
//==============================================================================
/** Fills the entire memory block with a repeated byte value.
This is handy for clearing a block of memory to zero.
*/
void fillWith (std::uint8_t valueToUse) noexcept;
/** Adds another block of data to the end of this one.
The data pointer must not be null. This block's size will be increased accordingly.
*/
void append (const void* data, size_t numBytes);
/** Resizes this block to the given size and fills its contents from the supplied buffer.
The data pointer must not be null.
*/
void replaceWith (const void* data, size_t numBytes);
/** Inserts some data into the block.
The dataToInsert pointer must not be null. This block's size will be increased accordingly.
If the insert position lies outside the valid range of the block, it will be clipped to
within the range before being used.
*/
void insert (const void* dataToInsert, size_t numBytesToInsert, size_t insertPosition);
/** Chops out a section of the block.
This will remove a section of the memory block and close the gap around it,
shifting any subsequent data downwards and reducing the size of the block.
If the range specified goes beyond the size of the block, it will be clipped.
*/
void removeSection (size_t startByte, size_t numBytesToRemove);
//==============================================================================
/** Copies data into this MemoryBlock from a memory address.
@param srcData the memory location of the data to copy into this block
@param destinationOffset the offset in this block at which the data being copied should begin
@param numBytes how much to copy in (if this goes beyond the size of the memory block,
it will be clipped so not to do anything nasty)
*/
void copyFrom (const void* srcData,
int destinationOffset,
size_t numBytes) noexcept;
/** Copies data from this MemoryBlock to a memory address.
@param destData the memory location to write to
@param sourceOffset the offset within this block from which the copied data will be read
@param numBytes how much to copy (if this extends beyond the limits of the memory block,
zeros will be used for that portion of the data)
*/
void copyTo (void* destData,
int sourceOffset,
size_t numBytes) const noexcept;
//==============================================================================
/** Exchanges the contents of this and another memory block.
No actual copying is required for this, so it's very fast.
*/
void swapWith (MemoryBlock& other) noexcept;
//==============================================================================
/** Attempts to parse the contents of the block as a zero-terminated UTF8 string. */
String toString() const;
//==============================================================================
/** Parses a string of hexadecimal numbers and writes this data into the memory block.
The block will be resized to the number of valid bytes read from the string.
Non-hex characters in the string will be ignored.
@see String::toHexString()
*/
void loadFromHexString (const String& sourceHexString);
//==============================================================================
/** Sets a number of bits in the memory block, treating it as a long binary sequence. */
void setBitRange (size_t bitRangeStart,
size_t numBits,
int binaryNumberToApply) noexcept;
/** Reads a number of bits from the memory block, treating it as one long binary sequence */
int getBitRange (size_t bitRangeStart,
size_t numBitsToRead) const noexcept;
//==============================================================================
/** Returns a string of characters that represent the binary contents of this block.
Uses a 64-bit encoding system to allow binary data to be turned into a string
of simple non-extended characters, e.g. for storage in XML.
@see fromBase64Encoding
*/
String toBase64Encoding() const;
/** Takes a string of encoded characters and turns it into binary data.
The string passed in must have been created by to64BitEncoding(), and this
block will be resized to recreate the original data block.
@see toBase64Encoding
*/
bool fromBase64Encoding (const String& encodedString);
private:
//==============================================================================
HeapBlock <char> data;
size_t size;
};
} // beast
#endif

View File

@@ -1,83 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
Result::Result() noexcept {}
Result::Result (const String& message) noexcept
: errorMessage (message)
{
}
Result::Result (const Result& other)
: errorMessage (other.errorMessage)
{
}
Result& Result::operator= (const Result& other)
{
errorMessage = other.errorMessage;
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
Result::Result (Result&& other) noexcept
: errorMessage (static_cast <String&&> (other.errorMessage))
{
}
Result& Result::operator= (Result&& other) noexcept
{
errorMessage = static_cast <String&&> (other.errorMessage);
return *this;
}
#endif
bool Result::operator== (const Result& other) const noexcept
{
return errorMessage == other.errorMessage;
}
bool Result::operator!= (const Result& other) const noexcept
{
return errorMessage != other.errorMessage;
}
Result Result::fail (const String& errorMessage) noexcept
{
return Result (errorMessage.isEmpty() ? "Unknown error" : errorMessage);
}
const String& Result::getErrorMessage() const noexcept
{
return errorMessage;
}
bool Result::wasOk() const noexcept { return errorMessage.isEmpty(); }
Result::operator bool() const noexcept { return errorMessage.isEmpty(); }
bool Result::failed() const noexcept { return errorMessage.isNotEmpty(); }
bool Result::operator!() const noexcept { return errorMessage.isNotEmpty(); }
} // beast

Some files were not shown because too many files have changed in this diff Show More