Compare commits

...

28 Commits

Author SHA1 Message Date
b6b31818aa [RELEASE] Release v1.0.0 2021-02-16 21:43:02 +01:00
681f65a6c4 [DEBUG] update new API of lutin log 2019-05-03 10:18:22 +02:00
540aab40d4 [DEV] space correction 2019-04-01 21:57:43 +02:00
79c20a74ea [DEV] update nullptr in null (specific etk) 2018-06-19 22:15:52 +02:00
1617790e48 [DEV] add querry element in the request 2018-04-13 00:09:31 +02:00
5e422227ab [DEV] add option header' 2018-04-11 22:53:19 +02:00
273982e7d3 [DEV] add pourcentage enoding for URI in HTTP 2018-04-04 23:10:58 +02:00
212731101e [DEBUG] correct multiple argument error 2017-11-07 10:17:56 +01:00
b6d77a7910 [DEV] update to the new ETK allocator wrapper 2017-10-21 19:05:21 +02:00
c653ed5b4b [DEV] set websocket support the reconnection to an other server after http rediredt event 2017-10-14 10:49:26 +02:00
6ec43d60ed [DEV] add the capability to the HTTP to reconnect on an other client socket (not availlable for server mode) 2017-10-14 10:48:31 +02:00
e6f2d8041b [DEV] add parse of the remote TCP connection name in Linux 2017-10-14 10:47:35 +02:00
34bd74c67f [DEV] add the remote name connected to the TCP element IP:port 2017-10-14 10:46:32 +02:00
19ab3637cf [DEV] add client connection with unique string IP:port 2017-10-14 10:45:25 +02:00
790c165268 [DEBUG] update new Map 2017-09-26 15:48:25 +02:00
cb097b3ce5 [DEV] continue removing STL 2017-09-14 00:59:21 +02:00
73c73ef1f5 [DEV] remove STL 2017-09-07 23:38:26 +02:00
29607a6d46 [DEV] continue removing stl 2017-08-28 00:04:49 +02:00
54a5b66436 [DEBUG] missing functionnal 2017-06-07 00:25:35 +00:00
d260646f29 [DEBUG] correct an init and check of error in HTTP 2017-04-28 21:21:25 +02:00
36e7081920 [DEV] try to stabilize interface TCP 2017-04-27 21:47:42 +02:00
63c9757a50 [DEBUG] correct some double sent in a socket 2017-02-07 21:23:41 +01:00
0f4bbb87f7 Change licence APACHE-2 to MPL-2 ==> force source redistribution and permit static link 2017-01-05 21:28:23 +01:00
65ff5fb439 [DEV] change Time type std::chrono to echrono 2017-01-04 22:22:25 +01:00
85c8aeaad8 [DEV] add log in error multiple frame 2016-12-15 21:00:31 +01:00
39660fae32 [DEBUG] correct the stop sequence 2016-12-08 21:01:37 +01:00
18a4b7f72b [DEV] simplify code 2016-11-21 21:56:55 +01:00
2911d1c411 [DEV] update dev tag version 2016-10-23 23:20:07 +02:00
41 changed files with 1440 additions and 480 deletions

373
LICENSE Normal file
View File

@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

View File

@ -65,15 +65,15 @@ Compile software:
lutin -C -P enet-test?build?run
License (APACHE v2.0)
License (MPL v2.0)
=====================
Copyright enet Edouard DUPIN
Licensed under the Apache License, Version 2.0 (the "License");
Licensed under the Mozilla Public License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
https://www.mozilla.org/MPL/2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,

View File

@ -38,16 +38,16 @@ Are there any licensing restrictions? {#enet_mainpage_license_restric
ENET is **FREE software** and _all sub-library are FREE and staticly linkable !!!_
License (APACHE-2.0) {#enet_mainpage_license}
====================
License (MPL v2.0) {#enet_mainpage_license}
==================
Copyright ENET Edouard DUPIN
Licensed under the Apache License, Version 2.0 (the "License");
Licensed under the Mozilla Public License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
<http://www.apache.org/licenses/LICENSE-2.0>
<https://www.mozilla.org/MPL/2.0>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,

View File

@ -1,9 +1,8 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/debug.hpp>
#include <enet/Ftp.hpp>
#include <cstring>

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once

View File

@ -1,24 +1,29 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/debug.hpp>
#include <enet/Http.hpp>
#include <map>
#include <etk/Map.hpp>
#include <etk/Stream.hpp>
#include <etk/stdTools.hpp>
#include <cstring>
#include <enet/TcpClient.hpp>
#include <enet/pourcentEncoding.hpp>
extern "C" {
#include <string.h>
}
static std::string escapeChar(const std::string& _value) {
static etk::String escapeChar(const etk::String& _value) {
return _value;
}
static std::string unEscapeChar(const std::string& _value) {
static etk::String unEscapeChar(const etk::String& _value) {
return _value;
}
static std::string removeStartAndStopSpace(const std::string& _value) {
std::string out;
static etk::String removeStartAndStopSpace(const etk::String& _value) {
etk::String out;
out.reserve(_value.size());
bool findSpace = false;
for (auto &it : _value) {
@ -36,64 +41,71 @@ static std::string removeStartAndStopSpace(const std::string& _value) {
return out;
}
static std::map<enet::HTTPAnswerCode, std::string> protocolName = {
{enet::HTTPAnswerCode::c100_continue, "Continue"},
{enet::HTTPAnswerCode::c101_switchingProtocols, "Switching Protocols"},
{enet::HTTPAnswerCode::c103_checkpoint, "Checkpoint"},
{enet::HTTPAnswerCode::c200_ok, "OK"},
{enet::HTTPAnswerCode::c201_created, "Created"},
{enet::HTTPAnswerCode::c202_accepted, "Accepted"},
{enet::HTTPAnswerCode::c203_nonAuthoritativeInformation, "Non-Authoritative Information"},
{enet::HTTPAnswerCode::c204_noContent, "No Content"},
{enet::HTTPAnswerCode::c205_resetContent, "Reset Content"},
{enet::HTTPAnswerCode::c206_partialContent, "Partial Content"},
{enet::HTTPAnswerCode::c300_multipleChoices, "Multiple Choices"},
{enet::HTTPAnswerCode::c301_movedPermanently, "Moved Permanently"},
{enet::HTTPAnswerCode::c302_found, "Found"},
{enet::HTTPAnswerCode::c303_seeOther, "See Other"},
{enet::HTTPAnswerCode::c304_notModified, "Not Modified"},
{enet::HTTPAnswerCode::c306_switchProxy, "Switch Proxy"},
{enet::HTTPAnswerCode::c307_temporaryRedirect, "Temporary Redirect"},
{enet::HTTPAnswerCode::c308_resumeIncomplete, "Resume Incomplete"},
{enet::HTTPAnswerCode::c400_badRequest, "Bad Request"},
{enet::HTTPAnswerCode::c401_unauthorized, "Unauthorized"},
{enet::HTTPAnswerCode::c402_paymentRequired, "Payment Required"},
{enet::HTTPAnswerCode::c403_forbidden, "Forbidden"},
{enet::HTTPAnswerCode::c404_notFound, "Not Found"},
{enet::HTTPAnswerCode::c405_methodNotAllowed, "Method Not Allowed"},
{enet::HTTPAnswerCode::c406_notAcceptable, "Not Acceptable"},
{enet::HTTPAnswerCode::c407_proxyAuthenticationRequired, "Proxy Authentication Required"},
{enet::HTTPAnswerCode::c408_requestTimeout, "Request Timeout"},
{enet::HTTPAnswerCode::c409_conflict, "Conflict"},
{enet::HTTPAnswerCode::c410_gone, "Gone"},
{enet::HTTPAnswerCode::c411_lengthRequired, "Length Required"},
{enet::HTTPAnswerCode::c412_preconditionFailed, "Precondition Failed"},
{enet::HTTPAnswerCode::c413_requestEntityTooLarge, "Request Entity Too Large"},
{enet::HTTPAnswerCode::c414_requestURITooLong, "Request-URI Too Long"},
{enet::HTTPAnswerCode::c415_unsupportedMediaType, "Unsupported Media Type"},
{enet::HTTPAnswerCode::c416_requestedRangeNotSatisfiable, "Requested Range Not Satisfiable"},
{enet::HTTPAnswerCode::c417_expectationFailed, "Expectation Failed"},
{enet::HTTPAnswerCode::c500_internalServerError, "Internal Server Error"},
{enet::HTTPAnswerCode::c501_notImplemented, "Not Implemented"},
{enet::HTTPAnswerCode::c502_badGateway, "Bad Gateway"},
{enet::HTTPAnswerCode::c503_serviceUnavailable, "Service Unavailable"},
{enet::HTTPAnswerCode::c504_gatewayTimeout, "Gateway Timeout"},
{enet::HTTPAnswerCode::c505_httpVersionNotSupported, "HTTP Version Not Supported"},
{enet::HTTPAnswerCode::c511_networkAuthenticationRequired, "Network Authentication Required"}
static const etk::Map<enet::HTTPAnswerCode, etk::String>& getProtocolName() {
static etk::Map<enet::HTTPAnswerCode, etk::String> protocolName;
static bool isInit = false;
if (isInit == true) {
return protocolName;
}
isInit = true;
protocolName.add(enet::HTTPAnswerCode::c100_continue, "Continue");
protocolName.add(enet::HTTPAnswerCode::c101_switchingProtocols, "Switching Protocols");
protocolName.add(enet::HTTPAnswerCode::c103_checkpoint, "Checkpoint");
protocolName.add(enet::HTTPAnswerCode::c200_ok, "OK");
protocolName.add(enet::HTTPAnswerCode::c201_created, "Created");
protocolName.add(enet::HTTPAnswerCode::c202_accepted, "Accepted");
protocolName.add(enet::HTTPAnswerCode::c203_nonAuthoritativeInformation, "Non-Authoritative Information");
protocolName.add(enet::HTTPAnswerCode::c204_noContent, "No Content");
protocolName.add(enet::HTTPAnswerCode::c205_resetContent, "Reset Content");
protocolName.add(enet::HTTPAnswerCode::c206_partialContent, "Partial Content");
protocolName.add(enet::HTTPAnswerCode::c300_multipleChoices, "Multiple Choices");
protocolName.add(enet::HTTPAnswerCode::c301_movedPermanently, "Moved Permanently");
protocolName.add(enet::HTTPAnswerCode::c302_found, "Found");
protocolName.add(enet::HTTPAnswerCode::c303_seeOther, "See Other");
protocolName.add(enet::HTTPAnswerCode::c304_notModified, "Not Modified");
protocolName.add(enet::HTTPAnswerCode::c306_switchProxy, "Switch Proxy");
protocolName.add(enet::HTTPAnswerCode::c307_temporaryRedirect, "Temporary Redirect");
protocolName.add(enet::HTTPAnswerCode::c308_resumeIncomplete, "Resume Incomplete");
protocolName.add(enet::HTTPAnswerCode::c400_badRequest, "Bad Request");
protocolName.add(enet::HTTPAnswerCode::c401_unauthorized, "Unauthorized");
protocolName.add(enet::HTTPAnswerCode::c402_paymentRequired, "Payment Required");
protocolName.add(enet::HTTPAnswerCode::c403_forbidden, "Forbidden");
protocolName.add(enet::HTTPAnswerCode::c404_notFound, "Not Found");
protocolName.add(enet::HTTPAnswerCode::c405_methodNotAllowed, "Method Not Allowed");
protocolName.add(enet::HTTPAnswerCode::c406_notAcceptable, "Not Acceptable");
protocolName.add(enet::HTTPAnswerCode::c407_proxyAuthenticationRequired, "Proxy Authentication Required");
protocolName.add(enet::HTTPAnswerCode::c408_requestTimeout, "Request Timeout");
protocolName.add(enet::HTTPAnswerCode::c409_conflict, "Conflict");
protocolName.add(enet::HTTPAnswerCode::c410_gone, "Gone");
protocolName.add(enet::HTTPAnswerCode::c411_lengthRequired, "Length Required");
protocolName.add(enet::HTTPAnswerCode::c412_preconditionFailed, "Precondition Failed");
protocolName.add(enet::HTTPAnswerCode::c413_requestEntityTooLarge, "Request Entity Too Large");
protocolName.add(enet::HTTPAnswerCode::c414_requestURITooLong, "Request-URI Too Long");
protocolName.add(enet::HTTPAnswerCode::c415_unsupportedMediaType, "Unsupported Media Type");
protocolName.add(enet::HTTPAnswerCode::c416_requestedRangeNotSatisfiable, "Requested Range Not Satisfiable");
protocolName.add(enet::HTTPAnswerCode::c417_expectationFailed, "Expectation Failed");
protocolName.add(enet::HTTPAnswerCode::c500_internalServerError, "Internal Server Error");
protocolName.add(enet::HTTPAnswerCode::c501_notImplemented, "Not Implemented");
protocolName.add(enet::HTTPAnswerCode::c502_badGateway, "Bad Gateway");
protocolName.add(enet::HTTPAnswerCode::c503_serviceUnavailable, "Service Unavailable");
protocolName.add(enet::HTTPAnswerCode::c504_gatewayTimeout, "Gateway Timeout");
protocolName.add(enet::HTTPAnswerCode::c505_httpVersionNotSupported, "HTTP Version Not Supported");
protocolName.add(enet::HTTPAnswerCode::c511_networkAuthenticationRequired, "Network Authentication Required");
return protocolName;
};
static std::map<int32_t, std::string> getErrorList() {
static std::map<int32_t, std::string> g_list;
static etk::Map<int32_t, etk::String> getErrorList() {
static etk::Map<int32_t, etk::String> g_list;
return g_list;
}
enet::Http::Http(enet::Tcp _connection, bool _isServer) :
m_isServer(_isServer),
m_connection(std::move(_connection)),
m_connection(etk::move(_connection)),
m_headerIsSend(false),
m_thread(nullptr),
m_thread(null),
m_threadRunning(false) {
//setSendHeaderProperties("User-Agent", "e-net (ewol network interface)");
/*
@ -116,16 +128,18 @@ void enet::Http::threadCallback() {
// READ section data:
if (m_headerIsSend == false) {
getHeader();
m_headerIsSend = true;
if (m_headerIsSend == false) {
continue;
}
}
if (m_observerRaw != nullptr) {
if (m_observerRaw != null) {
m_observerRaw(m_connection);
} else {
m_temporaryBuffer.resize(67000);
int32_t len = m_connection.read(&m_temporaryBuffer[0], m_temporaryBuffer.size());
if (len > 0) {
ENET_INFO("Call client with datas ...");
if (m_observer != nullptr) {
if (m_observer != null) {
m_observer(m_temporaryBuffer);
}
}
@ -135,19 +149,28 @@ void enet::Http::threadCallback() {
ENET_DEBUG("End of thread HTTP");
}
void enet::Http::redirectTo(const etk::String& _addressRedirect, bool _inThreadStop) {
if (m_isServer == true) {
ENET_ERROR("Request a redirect in Server mode ==> not authorised");
return;
}
stop(_inThreadStop);
m_headerIsSend = false;
m_connection = etk::move(connectTcpClient(_addressRedirect, 5, echrono::seconds(1)));
}
void enet::Http::start() {
ENET_DEBUG("connect [START]");
m_threadRunning = true;
m_thread = new std::thread([&](void *){ this->threadCallback();}, nullptr);
if (m_thread == nullptr) {
m_thread = ETK_NEW(ethread::Thread, [&](){ threadCallback();});
if (m_thread == null) {
m_threadRunning = false;
ENET_ERROR("creating callback thread!");
return;
}
while ( m_threadRunning == true
&& m_connection.getConnectionStatus() != enet::Tcp::status::link) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
ethread::sleepMilliSeconds((50));
}
//ethread::setPriority(*m_receiveThread, -6);
ENET_DEBUG("connect [STOP]");
@ -166,21 +189,23 @@ void enet::Http::stop(bool _inThreadStop){
m_connection.unlink();
}
if (_inThreadStop == false) {
if (m_thread != nullptr) {
if (m_thread != null) {
ENET_DEBUG("wait join Thread ...");
m_thread->join();
delete m_thread;
m_thread = nullptr;
ENET_DEBUG("wait join Thread (done)");
ETK_DELETE(ethread::Thread, m_thread);
m_thread = null;
}
}
ENET_DEBUG("disconnect [STOP]");
}
/*
void enet::Http::writeAnswerHeader(enum enet::HTTPAnswerCode _value) {
std::string out;
etk::String out;
out = "HTTP/1.1 ";
out += etk::to_string(int32_t(_value));
auto it = protocolName.find(_value);
if (it == protocolName.end() ) {
out += etk::toString(int32_t(_value));
auto it = getProtocolName().find(_value);
if (it == getProtocolName().end() ) {
out += " ???";
} else {
out += " " + it->second;
@ -192,10 +217,10 @@ void enet::Http::writeAnswerHeader(enum enet::HTTPAnswerCode _value) {
*/
namespace etk {
template <>
bool from_string<enum enet::HTTPAnswerCode>(enum enet::HTTPAnswerCode& _variableRet, const std::string& _value) {
bool from_string<enum enet::HTTPAnswerCode>(enum enet::HTTPAnswerCode& _variableRet, const etk::String& _value) {
_variableRet = enet::HTTPAnswerCode::c000_unknow;
for (auto &it : protocolName) {
if (etk::to_string(int32_t(it.first)) == _value) {
for (auto &it : getProtocolName()) {
if (etk::toString(int32_t(it.first)) == _value) {
_variableRet = it.first;
return true;
}
@ -203,11 +228,11 @@ namespace etk {
return false;
}
template <>
std::string to_string<enum enet::HTTPAnswerCode>(const enum enet::HTTPAnswerCode& _value) {
return etk::to_string(int32_t(_value));
etk::String toString<enum enet::HTTPAnswerCode>(const enum enet::HTTPAnswerCode& _value) {
return etk::toString(int32_t(_value));
}
template <>
bool from_string<enum enet::HTTPReqType>(enum enet::HTTPReqType& _variableRet, const std::string& _value) {
bool from_string<enum enet::HTTPReqType>(enum enet::HTTPReqType& _variableRet, const etk::String& _value) {
_variableRet = enet::HTTPReqType::HTTP_GET;
if (_value == "GET") {
_variableRet = enet::HTTPReqType::HTTP_GET;
@ -224,22 +249,26 @@ namespace etk {
} else if (_value == "DELETE") {
_variableRet = enet::HTTPReqType::HTTP_DELETE;
return true;
} else if (_value == "OPTIONS") {
_variableRet = enet::HTTPReqType::HTTP_OPTIONS;
return true;
}
return false;
}
template <>
std::string to_string<enum enet::HTTPReqType>(const enum enet::HTTPReqType& _value) {
etk::String toString<enum enet::HTTPReqType>(const enum enet::HTTPReqType& _value) {
switch (_value) {
case enet::HTTPReqType::HTTP_GET: return "GET";
case enet::HTTPReqType::HTTP_HEAD: return "HEAD";
case enet::HTTPReqType::HTTP_POST: return "POST";
case enet::HTTPReqType::HTTP_PUT: return "PUT";
case enet::HTTPReqType::HTTP_DELETE: return "DELETE";
case enet::HTTPReqType::HTTP_OPTIONS: return "OPTIONS";
}
return "UNKNOW";
}
template <>
bool from_string<enum enet::HTTPProtocol>(enum enet::HTTPProtocol& _variableRet, const std::string& _value) {
bool from_string<enum enet::HTTPProtocol>(enum enet::HTTPProtocol& _variableRet, const etk::String& _value) {
_variableRet = enet::HTTPProtocol::http_0_1;
if (_value == "HTTP/0.1") { _variableRet = enet::HTTPProtocol::http_0_1; return true; }
if (_value == "HTTP/0.2") { _variableRet = enet::HTTPProtocol::http_0_2; return true; }
@ -287,7 +316,7 @@ namespace etk {
return false;
}
template <>
std::string to_string<enum enet::HTTPProtocol>(const enum enet::HTTPProtocol& _value) {
etk::String toString<enum enet::HTTPProtocol>(const enum enet::HTTPProtocol& _value) {
switch (_value) {
case enet::HTTPProtocol::http_0_1: return "HTTP/0.1";
case enet::HTTPProtocol::http_0_2: return "HTTP/0.2";
@ -340,31 +369,43 @@ namespace etk {
void enet::Http::setRequestHeader(const enet::HttpRequest& _req) {
m_requestHeader = _req;
if (m_requestHeader.getKey("User-Agent") == "") {
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
if (m_isServer == true) {
if (m_requestHeader.getKey("Server") == "") {
m_requestHeader.setKey("Server", "e-net (ewol network interface)");
}
} else {
if (m_requestHeader.getKey("User-Agent") == "") {
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
}
}
std::string value = m_requestHeader.generate();
etk::String value = m_requestHeader.generate();
write(value, false);
}
void enet::Http::setAnswerHeader(const enet::HttpAnswer& _req) {
m_answerHeader = _req;
if (m_requestHeader.getKey("User-Agent") == "") {
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
if (m_isServer == true) {
if (m_requestHeader.getKey("Server") == "") {
m_requestHeader.setKey("Server", "e-net (ewol network interface)");
}
} else {
if (m_requestHeader.getKey("User-Agent") == "") {
m_requestHeader.setKey("User-Agent", "e-net (ewol network interface)");
}
}
std::string value = m_answerHeader.generate();
etk::String value = m_answerHeader.generate();
write(value, false);
}
void enet::Http::getHeader() {
ENET_VERBOSE("Read HTTP Header [START]");
bool headerEnded = false;
std::string header;
etk::String header;
while (m_connection.getConnectionStatus() == enet::Tcp::status::link) {
char type;
char type = '?';
int32_t len = m_connection.read(&type, 1);
if (len == 0) {
std::this_thread::sleep_for(std::chrono::microseconds(1));
ethread::sleepMilliSeconds(1);
continue;
}
header += type;
@ -394,7 +435,7 @@ void enet::Http::getHeader() {
ENET_VERBOSE("Read HTTP Header [STOP] : '" << header << "'");
m_headerIsSend = true;
// parse header :
std::vector<std::string> list = etk::split(header, '\n');
etk::Vector<etk::String> list = etk::split(header, '\n');
for (auto &it : list) {
if ( it.size()>0
&& it[it.size()-1] == '\r') {
@ -402,7 +443,7 @@ void enet::Http::getHeader() {
}
}
//parse first element:
std::vector<std::string> listLineOne = etk::split(list[0], ' ');
etk::Vector<etk::String> listLineOne = etk::split(list[0], ' ');
if (listLineOne.size() < 2) {
ENET_ERROR("can not parse answear : " << listLineOne);
// answer bad request and close connection ...
@ -414,7 +455,8 @@ void enet::Http::getHeader() {
|| listLineOne[0] == "POST"
|| listLineOne[0] == "HEAD"
|| listLineOne[0] == "DELETE"
|| listLineOne[0] == "PUT" ) ) {
|| listLineOne[0] == "PUT"
|| listLineOne[0] == "OPTIONS" ) ) {
// HTTP CALL
if (m_isServer == false) {
// can not have call in client mode
@ -430,7 +472,14 @@ void enet::Http::getHeader() {
etk::from_string(valueType, listLineOne[0]);
m_requestHeader.setType(valueType);
// get URI:
m_requestHeader.setUri(listLineOne[1]);
etk::String basicUri = listLineOne[1];
size_t pos = basicUri.find('?');
if (pos == etk::String::npos) {
m_requestHeader.setUri(listLineOne[1]);
} else {
m_requestHeader.setUri(basicUri.extract(0, pos));
m_requestHeader.setQuery(pourcentUriDecode(basicUri.extract(pos+1)));
}
// Get http version:
enum enet::HTTPProtocol valueProtocol;
etk::from_string(valueProtocol, listLineOne[2]);
@ -457,7 +506,7 @@ void enet::Http::getHeader() {
m_answerHeader.setErrorCode(valueErrorCode);
// get comment:
std::string comment;
etk::String comment;
for (size_t iii=2; iii<listLineOne.size(); ++iii) {
if (comment.size() != 0) {
comment += " ";
@ -476,13 +525,13 @@ void enet::Http::getHeader() {
}
for (size_t iii=1; iii<list.size(); ++iii) {
size_t found = list[iii].find(":");
if (found == std::string::npos) {
if (found == etk::String::npos) {
// nothing
continue;
}
std::string key = unEscapeChar(std::string(list[iii], 0, found));
etk::String key = unEscapeChar(etk::String(list[iii], 0, found));
key = removeStartAndStopSpace(key);
std::string value = unEscapeChar(std::string(list[iii], found+2));
etk::String value = unEscapeChar(etk::String(list[iii], found+2));
value = removeStartAndStopSpace(value);
ENET_VERBOSE("header : key='" << key << "' value='" << value << "'");
if (m_isServer == false) {
@ -496,12 +545,13 @@ void enet::Http::getHeader() {
m_connection.unlink();
}
}
m_headerIsSend = true;
if (m_isServer == false) {
if (m_observerAnswer != nullptr) {
if (m_observerAnswer != null) {
m_observerAnswer(m_answerHeader);
}
} else {
if (m_observerRequest != nullptr) {
if (m_observerRequest != null) {
m_observerRequest(m_requestHeader);
}
}
@ -509,9 +559,9 @@ void enet::Http::getHeader() {
/*
bool enet::Http::get(const std::string& _address) {
bool enet::Http::get(const etk::String& _address) {
m_header.m_map.clear();
std::string req = "GET http://" + m_connection.getName();
etk::String req = "GET http://" + m_connection.getName();
if (_address != "") {
req += "/";
req += _address;
@ -536,10 +586,10 @@ bool enet::Http::get(const std::string& _address) {
return false;
}
bool enet::Http::post(const std::string& _address, const std::map<std::string, std::string>& _values) {
bool enet::Http::post(const etk::String& _address, const etk::Map<etk::String, etk::String>& _values) {
m_header.m_map.clear();
// First create body :
std::string body;
etk::String body;
for (auto &it : _values) {
if (body.size() > 0) {
body += "&";
@ -549,16 +599,16 @@ bool enet::Http::post(const std::string& _address, const std::map<std::string, s
return post(_address, "application/x-www-form-urlencoded", body);
}
bool enet::Http::post(const std::string& _address, const std::string& _contentType, const std::string& _data) {
bool enet::Http::post(const etk::String& _address, const etk::String& _contentType, const etk::String& _data) {
m_header.m_map.clear();
std::string req = "POST http://" + m_connection.getName();
etk::String req = "POST http://" + m_connection.getName();
if (_address != "") {
req += "/";
req += _address;
}
req += " HTTP/1.0\n";
setSendHeaderProperties("Content-Type", _contentType);
setSendHeaderProperties("Content-Length", etk::to_string(_data.size()));
setSendHeaderProperties("Content-Length", etk::toString(_data.size()));
// add header properties :
for (auto &it : m_header.m_map) {
req += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n";
@ -583,23 +633,23 @@ int32_t enet::Http::write(const void* _data, int32_t _len) {
}
void enet::HttpHeader::setKey(const std::string& _key, const std::string& _value) {
void enet::HttpHeader::setKey(const etk::String& _key, const etk::String& _value) {
auto it = m_map.find(_key);
if (it == m_map.end()) {
m_map.insert(make_pair(_key, _value));
m_map.add(_key, _value);
} else {
it->second = _value;
}
}
void enet::HttpHeader::rmKey(const std::string& _key) {
void enet::HttpHeader::rmKey(const etk::String& _key) {
auto it = m_map.find(_key);
if (it != m_map.end()) {
m_map.erase(it);
}
}
std::string enet::HttpHeader::getKey(const std::string& _key) const {
etk::String enet::HttpHeader::getKey(const etk::String& _key) const {
auto it = m_map.find(_key);
if (it != m_map.end()) {
return it->second;
@ -607,17 +657,64 @@ std::string enet::HttpHeader::getKey(const std::string& _key) const {
return "";
}
std::string enet::HttpHeader::generateKeys() const {
std::string out;
bool enet::HttpHeader::existKey(const etk::String& _key) const {
auto it = m_map.find(_key);
if (it != m_map.end()) {
return true;
}
return false;
}
etk::String enet::HttpHeader::generateKeys() const {
etk::String out;
for (auto &it : m_map) {
if ( it.first != ""
&& it.second != "") {
out += escapeChar(it.first) + " : " + escapeChar(it.second) + "\r\n";
out += escapeChar(it.first) + ": " + escapeChar(it.second) + "\r\n";
}
}
return out;
}
void enet::HttpHeader::setQuery(const etk::Map<etk::String, etk::String>& _value) {
m_query = _value;
}
void enet::HttpHeader::setQueryKey(const etk::String& _key, const etk::String& _value) {
auto it = m_query.find(_key);
if (it == m_query.end()) {
m_query.add(_key, _value);
} else {
it->second = _value;
}
}
void enet::HttpHeader::rmQueryKey(const etk::String& _key) {
auto it = m_query.find(_key);
if (it != m_query.end()) {
m_query.erase(it);
}
}
etk::String enet::HttpHeader::getQueryKey(const etk::String& _key) const {
auto it = m_query.find(_key);
if (it != m_query.end()) {
return it->second;
}
return "";
}
bool enet::HttpHeader::existQueryKey(const etk::String& _key) const {
auto it = m_query.find(_key);
if (it != m_query.end()) {
return true;
}
return false;
}
etk::String enet::HttpHeader::generateQueryKeys() const {
return enet::pourcentUriEncode(m_query);
}
enet::HttpHeader::HttpHeader():
m_protocol(enet::HTTPProtocol::http_1_0) {
@ -627,7 +724,7 @@ enet::HttpHeader::HttpHeader():
// -----------------------------------------------------------------------------------------
enet::HttpAnswer::HttpAnswer(enum HTTPAnswerCode _code, const std::string& _help):
enet::HttpAnswer::HttpAnswer(enum HTTPAnswerCode _code, const etk::String& _help):
m_what(_code),
m_helpMessage(_help) {
@ -645,19 +742,26 @@ void enet::HttpAnswer::display() const {
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
}
}
ENET_PRINT(" query:");
for (auto &it : m_query) {
if ( it.first != ""
&& it.second != "") {
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
}
}
}
std::string enet::HttpAnswer::generate() const {
std::string out;
out += etk::to_string(m_protocol);
etk::String enet::HttpAnswer::generate() const {
etk::String out;
out += etk::toString(m_protocol);
out += " ";
out += etk::to_string(int32_t(m_what));
out += etk::toString(int32_t(m_what));
out += " ";
if (m_helpMessage != "") {
out += escapeChar(m_helpMessage);
} else {
auto it = protocolName.find(m_what);
if (it != protocolName.end()) {
auto it = getProtocolName().find(m_what);
if (it != getProtocolName().end()) {
out += escapeChar(it->second);
} else {
out += "???";
@ -669,12 +773,12 @@ std::string enet::HttpAnswer::generate() const {
return out;
}
enet::HttpServer::HttpServer(enet::Tcp _connection) :
enet::Http(std::move(_connection), true) {
enet::Http(etk::move(_connection), true) {
}
enet::HttpClient::HttpClient(enet::Tcp _connection) :
enet::Http(std::move(_connection), false) {
enet::Http(etk::move(_connection), false) {
}
// -----------------------------------------------------------------------------------------
@ -697,15 +801,26 @@ void enet::HttpRequest::display() const {
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
}
}
ENET_PRINT(" query:");
for (auto &it : m_query) {
if ( it.first != ""
&& it.second != "") {
ENET_PRINT(" '" + it.first + "' = '" + it.second + "'");
}
}
}
std::string enet::HttpRequest::generate() const {
std::string out;
out += etk::to_string(m_req);
etk::String enet::HttpRequest::generate() const {
etk::String out;
out += etk::toString(m_req);
out += " ";
out += m_uri;
etk::String querryData = generateQueryKeys();
if (querryData.empty() != 0) {
out += "?" + querryData;
}
out += " ";
out += etk::to_string(m_protocol);
out += etk::toString(m_protocol);
out += "\r\n";
out += generateKeys();
out += "\r\n";
@ -713,17 +828,17 @@ std::string enet::HttpRequest::generate() const {
}
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPProtocol _obj) {
_os << "enet::HTTPProtocol::" <<etk::to_string(_obj);
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPProtocol _obj) {
_os << "enet::HTTPProtocol::" <<etk::toString(_obj);
return _os;
}
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPAnswerCode _obj) {
_os << "enet::HTTPAnswerCode::" << etk::to_string(_obj);
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPAnswerCode _obj) {
_os << "enet::HTTPAnswerCode::" << etk::toString(_obj);
return _os;
}
std::ostream& enet::operator <<(std::ostream& _os, enum enet::HTTPReqType _obj) {
_os << "enet::HTTPReqType::" << etk::to_string(_obj);
etk::Stream& enet::operator <<(etk::Stream& _os, enum enet::HTTPReqType _obj) {
_os << "enet::HTTPReqType::" << etk::toString(_obj);
return _os;
}

View File

@ -1,15 +1,16 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <enet/Tcp.hpp>
#include <vector>
#include <map>
#include <thread>
#include <etk/Vector.hpp>
#include <etk/Map.hpp>
#include <ethread/Thread.hpp>
#include <ethread/tools.hpp>
#include <etk/Function.hpp>
namespace enet {
enum class HTTPAnswerCode {
@ -63,7 +64,7 @@ namespace enet {
c505_httpVersionNotSupported, //!< The server does not support the HTTP protocol version used in the request
c511_networkAuthenticationRequired, //!< The client needs to authenticate to gain network access
};
std::ostream& operator <<(std::ostream& _os, enum enet::HTTPAnswerCode _obj);
etk::Stream& operator <<(etk::Stream& _os, enum enet::HTTPAnswerCode _obj);
enum class HTTPProtocol {
http_0_1,
@ -110,18 +111,28 @@ namespace enet {
http_3_9,
http_3_10,
};
std::ostream& operator <<(std::ostream& _os, enum enet::HTTPProtocol _obj);
etk::Stream& operator <<(etk::Stream& _os, enum enet::HTTPProtocol _obj);
class HttpHeader {
protected:
// key, val
std::map<std::string, std::string> m_map;
etk::Map<etk::String, etk::String> m_map;
etk::Map<etk::String, etk::String> m_query;
enum HTTPProtocol m_protocol;
public:
void setKey(const std::string& _key, const std::string& _value);
void rmKey(const std::string& _key);
std::string getKey(const std::string& _key) const;
void setKey(const etk::String& _key, const etk::String& _value);
void rmKey(const etk::String& _key);
etk::String getKey(const etk::String& _key) const;
bool existKey(const etk::String& _key) const;
protected:
std::string generateKeys() const;
etk::String generateKeys() const;
public:
void setQuery(const etk::Map<etk::String, etk::String>& _value);
void setQueryKey(const etk::String& _key, const etk::String& _value);
void rmQueryKey(const etk::String& _key);
etk::String getQueryKey(const etk::String& _key) const;
bool existQueryKey(const etk::String& _key) const;
protected:
etk::String generateQueryKeys() const;
public:
enum HTTPProtocol getProtocol() const {
return m_protocol;
@ -131,27 +142,27 @@ namespace enet {
}
HttpHeader();
virtual ~HttpHeader() = default;
virtual std::string generate() const = 0;
virtual etk::String generate() const = 0;
};
class HttpAnswer : public HttpHeader {
private:
enet::HTTPAnswerCode m_what;
std::string m_helpMessage;
etk::String m_helpMessage;
public:
HttpAnswer(enum HTTPAnswerCode _code = enet::HTTPAnswerCode::c400_badRequest, const std::string& _help="");
HttpAnswer(enum HTTPAnswerCode _code = enet::HTTPAnswerCode::c400_badRequest, const etk::String& _help="");
void display() const;
std::string generate() const;
etk::String generate() const;
void setErrorCode(enum HTTPAnswerCode _value) {
m_what = _value;
}
enum HTTPAnswerCode getErrorCode() const {
return m_what;
}
void setHelp(const std::string& _value) {
void setHelp(const etk::String& _value) {
m_helpMessage = _value;
}
const std::string& getHelp() const {
const etk::String& getHelp() const {
return m_helpMessage;
}
};
@ -161,27 +172,28 @@ namespace enet {
HTTP_POST,
HTTP_PUT,
HTTP_DELETE,
HTTP_OPTIONS,
};
std::ostream& operator <<(std::ostream& _os, enum enet::HTTPReqType _obj);
etk::Stream& operator <<(etk::Stream& _os, enum enet::HTTPReqType _obj);
class HttpRequest : public HttpHeader {
private:
// key, val
enum HTTPReqType m_req;
std::string m_uri;
etk::String m_uri;
public:
HttpRequest(enum enet::HTTPReqType _type=enet::HTTPReqType::HTTP_GET);
void display() const;
std::string generate() const;
etk::String generate() const;
void setType(enum enet::HTTPReqType _value) {
m_req = _value;
}
enum enet::HTTPReqType getType() const{
return m_req;
}
void setUri(const std::string& _value) {
void setUri(const etk::String& _value) {
m_uri = _value;
}
const std::string& getUri() const {
const etk::String& getUri() const {
return m_uri;
}
};
@ -215,9 +227,17 @@ namespace enet {
protected:
enet::Tcp m_connection;
bool m_headerIsSend;
std::thread* m_thread;
ethread::Thread* m_thread;
bool m_threadRunning;
std::vector<uint8_t> m_temporaryBuffer;
etk::Vector<uint8_t> m_temporaryBuffer;
public:
/**
* @brief Get the adress of the connection source IP:port
* @return string with the remote address name.
*/
const etk::String& getRemoteAddress() const {
return m_connection.getRemoteName();
}
private:
void threadCallback();
private:
@ -229,7 +249,14 @@ namespace enet {
return m_connection.getConnectionStatus() == enet::Tcp::status::link;
}
public:
using Observer = std::function<void(std::vector<uint8_t>&)>; //!< Define an Observer: function pointer
/**
* @brief Redirect the current HTTP request to an other network address.
* @param[in] _addressRedirect new redirection address:port
* @param[in] _inThreadStop the http thread request an auto-stop.
*/
void redirectTo(const etk::String& _addressRedirect, bool _inThreadStop=false);
public:
using Observer = etk::Function<void(etk::Vector<uint8_t>&)>; //!< Define an Observer: function pointer
Observer m_observer;
/**
* @brief Connect an function member on the signal with the shared_ptr object.
@ -238,8 +265,8 @@ namespace enet {
* @param[in] _args Argument optinnal the user want to add.
*/
template<class CLASS_TYPE>
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(std::vector<uint8_t>&)) {
m_observer = [=](std::vector<uint8_t>& _value){
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(etk::Vector<uint8_t>&)) {
m_observer = [=](etk::Vector<uint8_t>& _value){
(*_class.*_func)(_value);
};
}
@ -247,7 +274,7 @@ namespace enet {
m_observer = _func;
}
public:
using ObserverRaw = std::function<void(enet::Tcp&)>; //!< Define an Observer: function pointer
using ObserverRaw = etk::Function<void(enet::Tcp&)>; //!< Define an Observer: function pointer
ObserverRaw m_observerRaw;
/**
* @brief Connect an function member on the signal with the shared_ptr object.
@ -265,11 +292,11 @@ namespace enet {
m_observerRaw = _func;
}
public:
using ObserverRequest = std::function<void(const enet::HttpRequest&)>; //!< Define an Observer: function pointer
using ObserverRequest = etk::Function<void(const enet::HttpRequest&)>; //!< Define an Observer: function pointer
protected:
ObserverRequest m_observerRequest;
public:
using ObserverAnswer = std::function<void(const enet::HttpAnswer&)>; //!< Define an Observer: function pointer
using ObserverAnswer = etk::Function<void(const enet::HttpAnswer&)>; //!< Define an Observer: function pointer
protected:
ObserverAnswer m_observerAnswer;
public:
@ -288,7 +315,7 @@ namespace enet {
* @return >0 byte size on the socket write
* @return -1 an error occured.
*/
int32_t write(const std::string& _data, bool _writeBackSlashZero = true) {
int32_t write(const etk::String& _data, bool _writeBackSlashZero = true) {
if (_data.size() == 0) {
return 0;
}
@ -305,7 +332,7 @@ namespace enet {
* @return -1 an error occured.
*/
template <class T>
int32_t write(const std::vector<T>& _data) {
int32_t write(const etk::Vector<T>& _data) {
if (_data.size() == 0) {
return 0;
}
@ -322,12 +349,13 @@ namespace enet {
HttpClient(enet::Tcp _connection);
public:
void setHeader(const enet::HttpRequest& _header) {
_header.display();
setRequestHeader(_header);
}
public:
//bool get(const std::string& _address);
//bool post(const std::string& _address, const std::map<std::string, std::string>& _values);
//bool post(const std::string& _address, const std::string& _contentType, const std::string& _data);
//bool get(const etk::String& _address);
//bool post(const etk::String& _address, const etk::Map<etk::String, etk::String>& _values);
//bool post(const etk::String& _address, const etk::String& _contentType, const etk::String& _data);
public:
/**
* @brief Connect an function member on the signal with the shared_ptr object.
@ -351,6 +379,7 @@ namespace enet {
HttpServer(enet::Tcp _connection);
public:
void setHeader(const enet::HttpAnswer& _header) {
_header.display();
setAnswerHeader(_header);
}
public:

View File

@ -1,16 +1,19 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/debug.hpp>
#include <enet/Tcp.hpp>
#include <sys/types.h>
#include <cerrno>
#include <unistd.h>
#include <cstring>
extern "C" {
#include <errno.h>
#include <unistd.h>
#include <string.h>
}
#include <etk/stdTools.hpp>
#include <ethread/tools.hpp>
#ifdef __TARGET_OS__Windows
#include <winsock2.h>
@ -22,6 +25,10 @@
#include <netdb.h>
#endif
#ifdef ENET_STORE_INPUT
static uint32_t baseID = 0;
#endif
bool enet::Tcp::setTCPNoDelay(bool _enabled) {
if (m_socketId >= 0) {
int flag = _enabled==true?1:0;
@ -46,20 +53,29 @@ enet::Tcp::Tcp() :
}
#ifdef __TARGET_OS__Windows
enet::Tcp::Tcp(SOCKET _idSocket, const std::string& _name) :
enet::Tcp::Tcp(SOCKET _idSocket, const etk::String& _name, const etk::String& _remoteName) :
#else
enet::Tcp::Tcp(int32_t _idSocket, const std::string& _name) :
enet::Tcp::Tcp(int32_t _idSocket, const etk::String& _name, const etk::String& _remoteName) :
#endif
m_socketId(_idSocket),
m_name(_name),
m_remoteName(_remoteName),
m_status(status::link) {
#ifdef ENET_STORE_INPUT
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
m_nodeStoreInput.fileOpenWrite();
#endif
}
enet::Tcp::Tcp(Tcp&& _obj) :
m_socketId(_obj.m_socketId),
m_name(_obj.m_name),
m_remoteName(_obj.m_remoteName),
m_status(_obj.m_status) {
#ifdef ENET_STORE_INPUT
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
m_nodeStoreInput.fileOpenWrite();
#endif
#ifdef __TARGET_OS__Windows
_obj.m_socketId = INVALID_SOCKET;
#else
@ -75,6 +91,10 @@ enet::Tcp::~Tcp() {
enet::Tcp& enet::Tcp::operator = (enet::Tcp&& _obj) {
unlink();
#ifdef ENET_STORE_INPUT
m_nodeStoreInput = etk::FSNode("CACHE:StoreTCPdata_" + etk::toString(baseID++) + ".tcp");
m_nodeStoreInput.fileOpenWrite();
#endif
m_socketId = _obj.m_socketId;
#ifdef __TARGET_OS__Windows
_obj.m_socketId = INVALID_SOCKET;
@ -89,20 +109,25 @@ enet::Tcp& enet::Tcp::operator = (enet::Tcp&& _obj) {
}
bool enet::Tcp::unlink() {
// prevent call while stoping ...
m_status = status::unlink;
if (m_socketId >= 0) {
ENET_INFO("Close socket (start)");
#ifdef __TARGET_OS__Windows
shutdown(m_socketId, SD_BOTH);
// Release hand of the socket to permit the Select to exit ... ==> otherwise it lock ...
ethread::sleepMilliSeconds((20));
closesocket(m_socketId);
m_socketId = INVALID_SOCKET;
#else
shutdown(m_socketId, SHUT_RDWR);
// Release hand of the socket to permit the Select to exit ... ==> otherwise it lock ...
ethread::sleepMilliSeconds((20));
close(m_socketId);
m_socketId = -1;
#endif
ENET_INFO("Close socket (done)");
}
m_status = status::unlink;
return true;
}
@ -121,7 +146,9 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
timeOutStruct.tv_usec = 0;
FD_ZERO(&sock);
FD_SET(m_socketId,&sock);
ENET_VERBOSE(" select ...");
int rc = select(m_socketId+1, &sock, NULL, NULL, &timeOutStruct);
ENET_VERBOSE(" select (done)");
// Check to see if the poll call failed.
if (rc < 0) {
ENET_ERROR(" select() failed");
@ -141,7 +168,7 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
// Receive data on this connection until the recv fails with EWOULDBLOCK.
// If any other failure occurs, we will close the connection.
{
std::unique_lock<std::mutex> lock(m_mutex);
ethread::UniqueLock lock(m_mutex);
rc = recv(m_socketId, (char *)_data, _maxLen, 0);
}
if (rc < 0) {
@ -154,6 +181,7 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
if (rc == 0) {
ENET_INFO("Connection closed");
closeConn = true;
size = 0;
}
if (closeConn == false) {
// Data was received
@ -164,7 +192,9 @@ int32_t enet::Tcp::read(void* _data, int32_t _maxLen) {
ENET_DEBUG(" Set status at remote close ...");
m_status = status::linkRemoteClose;
}
//#endif
#ifdef ENET_STORE_INPUT
m_nodeStoreInput.fileWrite(_data, 1, size);
#endif
return size;
}
@ -174,10 +204,23 @@ int32_t enet::Tcp::write(const void* _data, int32_t _len) {
ENET_ERROR("Can not write on unlink connection");
return -1;
}
if (_data == null) {
ENET_ERROR("try write null data on TCP socket");
return -1;
}
if (_len <= 0) {
if (_len == 0) {
ENET_WARNING("try write data with lenght=" << _len << " ==> bad case");
return 0;
}
ENET_ERROR("try write data with lenght=" << _len << " ==> bad case");
elog::displayBacktrace();
return -1;
}
//ENET_DEBUG("write on socketid = " << m_socketId << " data@=" << int64_t(_data) << " size=" << _len );
int32_t size;
{
std::unique_lock<std::mutex> lock(m_mutex);
ethread::UniqueLock lock(m_mutex);
size = ::send(m_socketId, (const char *)_data, _len, 0);
}
if ( size != _len

View File

@ -1,17 +1,24 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <mutex>
#include <ethread/Mutex.hpp>
#include <etk/Function.hpp>
#ifdef __TARGET_OS__Windows
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
//#define ENET_STORE_INPUT
#ifdef ENET_STORE_INPUT
#include <etk/os/FSNode.hpp>
#endif
namespace enet {
class Tcp {
private:
@ -20,13 +27,16 @@ namespace enet {
#else
int32_t m_socketId; //!< socket linux interface generic
#endif
std::mutex m_mutex;
#ifdef ENET_STORE_INPUT
etk::FSNode m_nodeStoreInput;
#endif
ethread::Mutex m_mutex;
public:
Tcp();
#ifdef __TARGET_OS__Windows
Tcp(SOCKET _idSocket, const std::string& _name);
Tcp(SOCKET _idSocket, const etk::String& _name, const etk::String& _remoteName="");
#else
Tcp(int32_t _idSocket, const std::string& _name);
Tcp(int32_t _idSocket, const etk::String& _name, const etk::String& _remoteName="");
#endif
// move constructor
Tcp(Tcp&& _obj);
@ -36,15 +46,25 @@ namespace enet {
Tcp& operator= (Tcp& _obj) = delete;
virtual ~Tcp();
private:
std::string m_name; //!< hostname/IP:port.
etk::String m_name; //!< hostname/IP:port.
public:
/**
* @brief Get the decriptive name hot the host:port
* @return the string requested
*/
const std::string& getName() {
const etk::String& getName() const {
return m_name;
}
private:
etk::String m_remoteName; //!< remote IP:port.
public:
/**
* @brief Get the decriptive name hot the host:port
* @return the string requested
*/
const etk::String& getRemoteName() const {
return m_remoteName;
}
public:
enum class status {
unlink,
@ -92,7 +112,7 @@ namespace enet {
* @return >0 byte size on the socket write
* @return -1 an error occured.
*/
int32_t write(const std::string& _data, bool _writeBackSlashZero = true) {
int32_t write(const etk::String& _data, bool _writeBackSlashZero = true) {
if (_data.size() == 0) {
return 0;
}
@ -109,7 +129,7 @@ namespace enet {
* @return -1 an error occured.
*/
template <class T>
int32_t write(const std::vector<T>& _data) {
int32_t write(const etk::Vector<T>& _data) {
if (_data.size() == 0) {
return 0;
}

View File

@ -1,17 +1,19 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/debug.hpp>
#include <enet/Tcp.hpp>
#include <enet/TcpClient.hpp>
#include <enet/enet.hpp>
#include <sys/types.h>
#include <cerrno>
#include <unistd.h>
#include <cstring>
extern "C" {
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
}
#include <etk/stdTools.hpp>
#ifdef __TARGET_OS__Windows
@ -19,34 +21,53 @@
#else
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry) {
std::string tmpname;
tmpname = etk::to_string(_ip1);
enet::Tcp enet::connectTcpClient(const etk::String& _config, uint32_t _numberRetry, echrono::Duration _timeOut) {
size_t pos = _config.find(':');
if (pos == etk::String::npos) {
return etk::move(enet::connectTcpClient(_config, 0, _numberRetry, _timeOut));
}
return etk::move(enet::connectTcpClient(_config.extract(0, pos),
etk::string_to_uint16_t(_config.extract(pos+1)),
_numberRetry,
_timeOut));
}
enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry, echrono::Duration _timeOut) {
etk::String tmpname;
tmpname = etk::toString(_ip1);
tmpname += ".";
tmpname += etk::to_string(_ip2);
tmpname += etk::toString(_ip2);
tmpname += ".";
tmpname += etk::to_string(_ip3);
tmpname += etk::toString(_ip3);
tmpname += ".";
tmpname += etk::to_string(_ip4);
return std::move(enet::connectTcpClient(tmpname, _port, _numberRetry));
tmpname += etk::toString(_ip4);
return etk::move(enet::connectTcpClient(tmpname, _port, _numberRetry, _timeOut));
}
#ifdef __TARGET_OS__Windows
enet::Tcp enet::connectTcpClient(const std::string& _hostname, uint16_t _port, uint32_t _numberRetry) {
enet::Tcp enet::connectTcpClient(const etk::String& _hostname, uint16_t _port, uint32_t _numberRetry, echrono::Duration _timeOut) {
if (enet::isInit() == false) {
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
return std::move(enet::Tcp());
return etk::move(enet::Tcp());
}
if (_hostname == "") {
ENET_ERROR("get connection wihtout hostname");
return etk::move(enet::Tcp());
}
SOCKET socketId = INVALID_SOCKET;
ENET_INFO("Start connection on " << _hostname << ":" << _port);
for(int32_t iii=0; iii<_numberRetry ;iii++) {
if (iii > 0) {
ethread::sleepMilliSeconds((200));
}
// open in Socket normal mode
socketId = socket(AF_INET, SOCK_STREAM, 0);
if (socketId < 0) {
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
std::this_thread::sleep_for(std::chrono::milliseconds(200));
continue;
}
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
@ -58,18 +79,17 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
struct addrinfo* result = nullptr;
std::string portValue = etk::to_string(_port);
struct addrinfo* result = null;
etk::String portValue = etk::toString(_port);
int iResult = getaddrinfo(_hostname.c_str(), portValue.c_str(), &hints, &result);
if (iResult != 0) {
ENET_ERROR("getaddrinfo failed with error: " << iResult);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
continue;
}
// Attempt to connect to an address until one succeeds
for(struct addrinfo* ptr=result;
ptr != nullptr;
ptr != null;
ptr=ptr->ai_next) {
ENET_DEBUG(" find one ...");
// Create a SOCKET for connecting to server
@ -92,7 +112,6 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
if (socketId == INVALID_SOCKET) {
ENET_ERROR("Unable to connect to server!");
std::this_thread::sleep_for(std::chrono::milliseconds(200));
continue;
} else {
break;
@ -100,34 +119,56 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
}
if (socketId == INVALID_SOCKET) {
ENET_ERROR("ERROR connecting ... (after all try)");
return std::move(enet::Tcp());
return etk::move(enet::Tcp());
}
ENET_DEBUG("Connection done");
return std::move(enet::Tcp(socketId, _hostname + ":" + etk::to_string(_port)));
return etk::move(enet::Tcp(socketId, _hostname + ":" + etk::toString(_port)));
}
#else
#include <sys/socket.h>
enet::Tcp enet::connectTcpClient(const std::string& _hostname, uint16_t _port, uint32_t _numberRetry) {
enet::Tcp enet::connectTcpClient(const etk::String& _hostname, uint16_t _port, uint32_t _numberRetry, echrono::Duration _timeOut) {
if (enet::isInit() == false) {
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
return std::move(enet::Tcp());
return etk::move(enet::Tcp());
}
if (_hostname == "") {
ENET_ERROR("get connection wihtout hostname");
return etk::move(enet::Tcp());
}
int32_t socketId = -1;
ENET_INFO("Start connection on " << _hostname << ":" << _port);
for(int32_t iii=0; iii<_numberRetry ;iii++) {
if (iii > 0) {
ethread::sleepMilliSeconds((200));
}
// open in Socket normal mode
socketId = socket(AF_INET, SOCK_STREAM, 0);
if (socketId < 0) {
ENET_ERROR("ERROR while opening socket : errno=" << errno << "," << strerror(errno));
std::this_thread::sleep_for(std::chrono::milliseconds(200));
continue;
}
ENET_INFO("Try connect on socket ... (" << iii+1 << "/" << _numberRetry << ")");
struct sockaddr_in servAddr;
struct hostent* server = gethostbyname(_hostname.c_str());
if (server == nullptr) {
struct hostent* server = null;
if ( _hostname.c_str()[0] >= '0'
&& _hostname.c_str()[0] <= '9') {
ENET_INFO("Calling gethostbyaddr with " << _hostname);
struct in_addr addr;
addr.s_addr = inet_addr(_hostname.c_str());
if (addr.s_addr == INADDR_NONE) {
ENET_ERROR("The IPv4 address entered must be a legal address" << _hostname.c_str());
return etk::move(enet::Tcp());
} else {
// TODO : This is deprecated use getaddrinfo like windows ...
server = gethostbyaddr((char *) &addr, 4, AF_INET);
}
} else {
ENET_INFO("Calling gethostbyname with " << _hostname);
// TODO : This is deprecated use getaddrinfo like windows ...
server = gethostbyname(_hostname.c_str());
}
if (server == null) {
ENET_ERROR("ERROR, no such host : " << _hostname);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
continue;
}
bzero((char *) &servAddr, sizeof(servAddr));
@ -135,7 +176,7 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
bcopy((char *)server->h_addr, (char *)&servAddr.sin_addr.s_addr, server->h_length);
servAddr.sin_port = htons(_port);
ENET_INFO("Start connexion ...");
if (connect(socketId, (struct sockaddr *)&servAddr,sizeof(servAddr)) != 0) {
if (connect(socketId, (struct sockaddr *)&servAddr, sizeof(servAddr)) != 0) {
if(errno != EINPROGRESS) {
if( errno != ENOENT
&& errno != EAGAIN
@ -150,18 +191,16 @@ enet::Tcp enet::connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8
socketId = -1;
}
ENET_ERROR("ERROR connecting, maybe retry ... errno=" << errno << "," << strerror(errno));
std::this_thread::sleep_for(std::chrono::milliseconds(200));
continue;
}
// if we are here ==> then the connextion is done corectly ...
break;
}
if (socketId<0) {
ENET_ERROR("ERROR connecting ... (after all try)");
return std::move(enet::Tcp());
return etk::move(enet::Tcp());
}
ENET_DEBUG("Connection done");
return std::move(enet::Tcp(socketId, _hostname + ":" + etk::to_string(_port)));
ENET_INFO("Connection done");
return etk::move(enet::Tcp(socketId, _hostname + ":" + etk::toString(_port)));
}
#endif

View File

@ -1,13 +1,15 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <enet/Tcp.hpp>
#include <echrono/Duration.hpp>
namespace enet {
enet::Tcp connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry=5);
enet::Tcp connectTcpClient(const std::string& _hostname, uint16_t _port, uint32_t _numberRetry=5);
enet::Tcp connectTcpClient(uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4, uint16_t _port, uint32_t _numberRetry=5, echrono::Duration _timeOut = echrono::seconds(1));
enet::Tcp connectTcpClient(const etk::String& _hostname, uint16_t _port, uint32_t _numberRetry=5, echrono::Duration _timeOut = echrono::seconds(1));
enet::Tcp connectTcpClient(const etk::String& _config, uint32_t _numberRetry, echrono::Duration _timeOut);
}

View File

@ -1,17 +1,19 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/debug.hpp>
#include <enet/Tcp.hpp>
#include <enet/TcpServer.hpp>
#include <enet/enet.hpp>
#include <sys/types.h>
#include <cerrno>
#include <unistd.h>
#include <cstring>
extern "C" {
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
}
#include <etk/stdTools.hpp>
#ifdef __TARGET_OS__Windows
@ -37,18 +39,18 @@ enet::TcpServer::~TcpServer() {
}
void enet::TcpServer::setIpV4(uint8_t _fist, uint8_t _second, uint8_t _third, uint8_t _quatro) {
std::string tmpname;
tmpname = etk::to_string(_fist);
etk::String tmpname;
tmpname = etk::toString(_fist);
tmpname += ".";
tmpname += etk::to_string(_second);
tmpname += etk::toString(_second);
tmpname += ".";
tmpname += etk::to_string(_third);
tmpname += etk::toString(_third);
tmpname += ".";
tmpname += etk::to_string(_quatro);
tmpname += etk::toString(_quatro);
setHostNane(tmpname);
}
void enet::TcpServer::setHostNane(const std::string& _name) {
void enet::TcpServer::setHostNane(const etk::String& _name) {
if (_name == m_host) {
return;
}
@ -70,7 +72,7 @@ void enet::TcpServer::setPort(uint16_t _port) {
}
ENET_INFO("Start connection on " << m_host << ":" << m_port);
struct addrinfo *result = nullptr;
struct addrinfo *result = null;
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
@ -79,8 +81,8 @@ void enet::TcpServer::setPort(uint16_t _port) {
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
std::string portValue = etk::to_string(m_port);
int iResult = getaddrinfo(nullptr, portValue.c_str(), &hints, &result);
etk::String portValue = etk::toString(m_port);
int iResult = getaddrinfo(null, portValue.c_str(), &hints, &result);
if (iResult != 0) {
ENET_ERROR("getaddrinfo failed with error: " << iResult);
return 1;
@ -153,7 +155,7 @@ void enet::TcpServer::setPort(uint16_t _port) {
enet::Tcp enet::TcpServer::waitNext() {
if (enet::isInit() == false) {
ENET_ERROR("Need call enet::init(...) before accessing to the socket");
return std::move(enet::Tcp());
return etk::move(enet::Tcp());
}
ENET_INFO("End binding Socket ... (start listen)");
#ifdef __TARGET_OS__Windows
@ -181,8 +183,57 @@ enet::Tcp enet::TcpServer::waitNext() {
return enet::Tcp();
}
ENET_INFO("End configuring Socket ... Find New one");
return enet::Tcp(socketIdClient, m_host + ":" + etk::to_string(m_port));
etk::String remoteAddress;
{
struct sockaddr_storage addr;
char ipstr[INET6_ADDRSTRLEN];
socklen_t len = sizeof(addr);
getpeername(socketIdClient, (struct sockaddr*)&addr, &len);
// deal with both IPv4 and IPv6:
if (addr.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
int port = ntohs(s->sin_port);
remoteAddress = etk::toString(s->sin_addr.s_addr&0xFF);
remoteAddress += ".";
remoteAddress += etk::toString((s->sin_addr.s_addr>>8)&0xFF);
remoteAddress += ".";
remoteAddress += etk::toString((s->sin_addr.s_addr>>16)&0xFF);
remoteAddress += ".";
remoteAddress += etk::toString((s->sin_addr.s_addr>>24)&0xFF);
remoteAddress += ":";
remoteAddress += etk::toString(port);
} else { // AF_INET6
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
int port = ntohs(s->sin6_port);
remoteAddress = etk::toHex(s->sin6_addr.s6_addr[0], 2);
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[1], 2);
remoteAddress += ".";
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[2], 2);
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[3], 2);
remoteAddress += ".";
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[4], 2);
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[5], 2);
remoteAddress += ".";
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[6], 2);
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[7], 2);
remoteAddress += ".";
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[8], 2);
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[9], 2);
remoteAddress += ".";
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[10], 2);
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[11], 2);
remoteAddress += ".";
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[12], 2);
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[13], 2);
remoteAddress += ".";
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[14], 2);
remoteAddress += etk::toHex(s->sin6_addr.s6_addr[15], 2);
remoteAddress += ":";
remoteAddress += etk::toString(port);
}
}
ENET_ERROR("End configuring Socket ... Find New one FROM " << remoteAddress);
return enet::Tcp(socketIdClient, m_host + ":" + etk::toString(m_port), remoteAddress);
}

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <enet/Tcp.hpp>
@ -26,7 +26,7 @@ namespace enet {
TcpServer();
virtual ~TcpServer();
private:
std::string m_host; //!< hostname/IP to connect with.
etk::String m_host; //!< hostname/IP to connect with.
public:
/**
* @brief Set the connection IP id.
@ -40,12 +40,12 @@ namespace enet {
* @brief set the Host name is the same things as set an Ip adress, but in test mode "127.0.0.1" or "localhost".
* @param[in] _name Host name to connect.
*/
void setHostNane(const std::string& _name);
void setHostNane(const etk::String& _name);
/**
* @brief Get the decriptive name hot the host
* @return the string requested
*/
const std::string& getHostName() {
const etk::String& getHostName() {
return m_host;
}
private:

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/debug.hpp>

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once

View File

@ -1,15 +1,15 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/debug.hpp>
#include <enet/WebSocket.hpp>
#include <map>
#include <etk/Map.hpp>
#include <etk/stdTools.hpp>
#include <cstring>
#include <random>
#include <etk/String.hpp>
#include <etk/tool.hpp>
#include <algue/base64.hpp>
#include <algue/sha1.hpp>
@ -29,54 +29,44 @@ namespace enet {
enet::WebSocket::WebSocket() :
m_connectionValidate(false),
m_interface(nullptr),
m_observer(nullptr),
m_observerUriCheck(nullptr) {
m_interface(null),
m_observer(null),
m_observerUriCheck(null) {
}
enet::WebSocket::WebSocket(enet::Tcp _connection, bool _isServer) :
m_connectionValidate(false),
m_interface(nullptr),
m_observer(nullptr),
m_observerUriCheck(nullptr) {
_connection.setTCPNoDelay(true);
if (_isServer == true) {
ememory::SharedPtr<enet::HttpServer> interface = ememory::makeShared<enet::HttpServer>(std::move(_connection));
m_interface = interface;
if (interface != nullptr) {
interface->connectHeader(this, &enet::WebSocket::onReceiveRequest);
}
} else {
ememory::SharedPtr<enet::HttpClient> interface = ememory::makeShared<enet::HttpClient>(std::move(_connection));
m_interface = interface;
if (interface != nullptr) {
interface->connectHeader(this, &enet::WebSocket::onReceiveAnswer);
}
m_interface(null),
m_observer(null),
m_observerUriCheck(null) {
setInterface(etk::move(_connection), _isServer);
}
const etk::String& enet::WebSocket::getRemoteAddress() const {
if (m_interface == null) {
static const etk::String tmpOut;
return tmpOut;
}
if (m_interface == nullptr) {
ENET_ERROR("can not create interface for the websocket");
return;
}
m_interface->connectRaw(this, &enet::WebSocket::onReceiveData);
return m_interface->getRemoteAddress();
}
void enet::WebSocket::setInterface(enet::Tcp _connection, bool _isServer) {
_connection.setTCPNoDelay(true);
if (_isServer == true) {
ememory::SharedPtr<enet::HttpServer> interface = ememory::makeShared<enet::HttpServer>(std::move(_connection));
ememory::SharedPtr<enet::HttpServer> interface = ememory::makeShared<enet::HttpServer>(etk::move(_connection));
m_interface = interface;
if (interface != nullptr) {
if (interface != null) {
interface->connectHeader(this, &enet::WebSocket::onReceiveRequest);
}
} else {
ememory::SharedPtr<enet::HttpClient> interface = ememory::makeShared<enet::HttpClient>(std::move(_connection));
ememory::SharedPtr<enet::HttpClient> interface = ememory::makeShared<enet::HttpClient>(etk::move(_connection));
m_interface = interface;
if (interface != nullptr) {
if (interface != null) {
interface->connectHeader(this, &enet::WebSocket::onReceiveAnswer);
}
}
if (m_interface == nullptr) {
if (m_interface == null) {
ENET_ERROR("can not create interface for the websocket");
return;
}
@ -84,84 +74,93 @@ void enet::WebSocket::setInterface(enet::Tcp _connection, bool _isServer) {
}
enet::WebSocket::~WebSocket() {
if (m_interface == nullptr) {
if (m_interface == null) {
return;
}
stop(true);
}
static std::string generateKey() {
// create dynamic key:
std::random_device rd;
std::mt19937 e2(rd());
std::uniform_real_distribution<> dist(0, 0xFF);
static etk::String generateKey() {
uint8_t dataKey[16];
// create dynamic key:
for (size_t iii=0; iii<16; ++iii) {
dataKey[iii] = uint8_t(dist(e2));
dataKey[iii] = uint8_t(etk::tool::urand(0,255));
}
return algue::base64::encode(dataKey, 16);
}
static std::string generateCheckKey(const std::string& _key) {
std::string out = _key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
std::vector<uint8_t> keyData = algue::sha1::encode(out);
static etk::String generateCheckKey(const etk::String& _key) {
etk::String out = _key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
etk::Vector<uint8_t> keyData = algue::sha1::encode(out);
return algue::base64::encode(keyData);
}
void enet::WebSocket::start(const std::string& _uri, const std::vector<std::string>& _listProtocols) {
if (m_interface == nullptr) {
void enet::WebSocket::start(const etk::String& _uri, const etk::Vector<etk::String>& _listProtocols) {
if (m_interface == null) {
ENET_ERROR("Nullptr interface ...");
return;
}
m_interface->start();
if (m_interface->isServer() == false) {
enet::HttpRequest req(enet::HTTPReqType::HTTP_GET);
req.setProtocol(enet::HTTPProtocol::http_1_1);
req.setUri(_uri);
req.setKey("Upgrade", "websocket");
req.setKey("Connection", "Upgrade");
m_checkKey = generateKey();
req.setKey("Sec-WebSocket-Key", m_checkKey); // this is an example key ...
m_checkKey = generateCheckKey(m_checkKey);
req.setKey("Sec-WebSocket-Version", "13");
req.setKey("Pragma", "no-cache");
req.setKey("Cache-Control", "no-cache");
std::string protocolList;
for (auto &it : _listProtocols) {
if (it == "") {
continue;
if (m_interface->isServer() == true) {
m_interface->start();
} else {
do {
m_redirectInProgress = false;
m_interface->start();
enet::HttpRequest req(enet::HTTPReqType::HTTP_GET);
req.setProtocol(enet::HTTPProtocol::http_1_1);
req.setUri(_uri);
req.setKey("Upgrade", "websocket");
req.setKey("Connection", "Upgrade");
m_checkKey = generateKey();
req.setKey("Sec-WebSocket-Key", m_checkKey); // this is an example key ...
m_checkKey = generateCheckKey(m_checkKey);
req.setKey("Sec-WebSocket-Version", "13");
req.setKey("Pragma", "no-cache");
req.setKey("Cache-Control", "no-cache");
etk::String protocolList;
for (auto &it : _listProtocols) {
if (it == "") {
continue;
}
if (protocolList != "") {
protocolList += ", ";
}
protocolList += it;
}
if (protocolList != "") {
protocolList += ", ";
req.setKey("Sec-WebSocket-Protocol", protocolList);
}
protocolList += it;
}
if (protocolList != "") {
req.setKey("Sec-WebSocket-Protocol", protocolList);
}
ememory::SharedPtr<enet::HttpClient> interface = ememory::dynamicPointerCast<enet::HttpClient>(m_interface);
if (interface != nullptr) {
interface->setHeader(req);
int32_t timeout = 500000; // 5 second
while (timeout>=0) {
if ( m_connectionValidate == true
|| m_interface->isAlive() == false) {
break;
ememory::SharedPtr<enet::HttpClient> interface = ememory::dynamicPointerCast<enet::HttpClient>(m_interface);
if (interface != null) {
interface->setHeader(req);
int32_t timeout = 500000; // 5 second
while ( timeout>=0
&& m_redirectInProgress == false) {
if ( m_connectionValidate == true
|| m_interface->isAlive() == false) {
break;
}
ethread::sleepMilliSeconds(10);
timeout--;
}
if (m_redirectInProgress == true) {
ENET_WARNING("Request a redirection (wait 500ms)");
ethread::sleepMilliSeconds(500);
ENET_WARNING("Request a redirection (wait-end)");
} else {
if ( m_connectionValidate == false
|| m_interface->isAlive() == false) {
ENET_ERROR("Connection refused by SERVER ...");
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
timeout--;
}
if ( m_connectionValidate == false
|| m_interface->isAlive() == false) {
ENET_ERROR("Connection refused by SERVER ...");
}
}
} while (m_redirectInProgress == true);
}
}
void enet::WebSocket::stop(bool _inThread) {
ENET_DEBUG("Stop interface ...");
if (m_interface == nullptr) {
if (m_interface == null) {
ENET_ERROR("Nullptr interface ...");
return;
}
@ -185,15 +184,18 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
ENET_VERBOSE("ReadRaw 2 [STOP]");
return;
}
m_lastReceive = std::chrono::steady_clock::now();
m_lastReceive = echrono::Steady::now();
if ((opcode & 0x80) == 0) {
ENET_ERROR("Multiple frames ... NOT managed ...");
ENET_ERROR("Multiple frames ... NOT managed ... : " << (opcode & 0x80) << (opcode & 0x40) << (opcode & 0x20) << (opcode & 0x10) << (opcode & 0x08) << (opcode & 0x04) << (opcode & 0x02) << (opcode & 0x01));
m_interface->stop(true);
return;
}
int8_t size1 = 0;
len = _connection.read(&size1, sizeof(uint8_t));
if (len <= 0) {
int32_t maxIteration = 50;
// We must get the payload size in all case ... ==> otherwise it create problems
while ( len <= 0
&& maxIteration > 0) {
if (len < 0) {
if (_connection.getConnectionStatus() == enet::Tcp::status::link) {
ENET_ERROR("Protocol error occured ...");
@ -204,6 +206,12 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
}
ENET_ERROR("Time out ... ==> not managed ...");
ENET_VERBOSE("ReadRaw 2 [STOP]");
len = _connection.read(&size1, sizeof(uint8_t));
maxIteration--;
}
if (maxIteration <= 0) {
ENET_ERROR("Can not read the Socket >> auto kill");
m_interface->stop(true);
return;
}
uint64_t totalSize = size1 & 0x7F;
@ -283,32 +291,32 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
// check opcode:
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_CLOSE) {
// Close the conection by remote:
ENET_INFO("Close connection by remote :");
ENET_WARNING("Close connection by remote :");
m_interface->stop(true);
return;
}
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PING) {
// Close the conection by remote:
ENET_DEBUG("Receive a ping (send a pong)");
ENET_WARNING("Receive a ping (send a pong)");
controlPong();
return;
}
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PONG) {
// Close the conection by remote:
ENET_DEBUG("Receive a pong");
ENET_WARNING("Receive a pong");
return;
}
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_TEXT) {
// Close the conection by remote:
ENET_DEBUG("Receive a Text(UTF-8) data " << m_buffer.size() << " Bytes");
if (m_observer != nullptr) {
ENET_WARNING("Receive a Text(UTF-8) data " << m_buffer.size() << " Bytes");
if (m_observer != null) {
m_observer(m_buffer, true);
}
return;
}
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_BINARY) {
// Close the conection by remote:
if (m_observer != nullptr) {
if (m_observer != null) {
m_observer(m_buffer, false);
}
return;
@ -316,8 +324,8 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
ENET_ERROR("ReadRaw [STOP] (no opcode manage ... " << int32_t(opcode & 0x0F));
}
static std::string removeStartAndStopSpace(const std::string& _value) {
std::string out;
static etk::String removeStartAndStopSpace(const etk::String& _value) {
etk::String out;
out.reserve(_value.size());
bool findSpace = false;
for (auto &it : _value) {
@ -337,7 +345,7 @@ static std::string removeStartAndStopSpace(const std::string& _value) {
void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
ememory::SharedPtr<enet::HttpServer> interface = ememory::dynamicPointerCast<enet::HttpServer>(m_interface);
if (interface == nullptr) {
if (interface == null) {
ENET_ERROR("Nullptr interface ...");
return;
}
@ -375,16 +383,29 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
return;
}
// parse all protocols:
std::vector<std::string> listProtocol;
etk::Vector<etk::String> listProtocol;
if (_data.getKey("Sec-WebSocket-Protocol") != "") {
listProtocol = etk::split(_data.getKey("Sec-WebSocket-Protocol"),',');
for (size_t iii=0; iii<listProtocol.size(); ++iii) {
listProtocol[iii] = removeStartAndStopSpace(listProtocol[iii]);
}
}
if (m_observerUriCheck != nullptr) {
if (m_observerUriCheck(_data.getUri(), listProtocol) == false) {
if (m_observerUriCheck != null) {
etk::String ret = m_observerUriCheck(_data.getUri(), listProtocol);
if (ret == "OK") {
// Nothing to do
} else if (ret.startWith("REDIRECT:") == true) {
ENET_INFO("Request redirection of HTTP/WebSocket connection to : '" << ret.extract(9, ret.size()) << "'");
enet::HttpAnswer answer(enet::HTTPAnswerCode::c307_temporaryRedirect);
answer.setProtocol(enet::HTTPProtocol::http_1_1);
answer.setKey("Location", ret.extract(9, ret.size()));
interface->setHeader(answer);
interface->stop(true);
return;
} else {
if (ret != "CLOSE") {
ENET_ERROR("UNKNOW return type of URI request: '" << ret << "'");
}
enet::HttpAnswer answer(enet::HTTPAnswerCode::c404_notFound);
answer.setProtocol(enet::HTTPProtocol::http_1_1);
answer.setKey("Connection", "close");
@ -397,7 +418,7 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
answer.setProtocol(enet::HTTPProtocol::http_1_1);
answer.setKey("Upgrade", "websocket");
answer.setKey("Connection", "Upgrade");
std::string answerKey = generateCheckKey(_data.getKey("Sec-WebSocket-Key"));
etk::String answerKey = generateCheckKey(_data.getKey("Sec-WebSocket-Key"));
answer.setKey("Sec-WebSocket-Accept", answerKey);
if (m_protocol != "") {
answer.setKey("Sec-WebSocket-Protocol", m_protocol);
@ -406,11 +427,19 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
}
void enet::WebSocket::onReceiveAnswer(const enet::HttpAnswer& _data) {
if (m_interface == nullptr) {
if (m_interface == null) {
ENET_ERROR("Nullptr interface ...");
return;
}
_data.display();
if (_data.getErrorCode() == enet::HTTPAnswerCode::c307_temporaryRedirect) {
ENET_ERROR("Request connection redirection to '" << _data.getKey("Location") << "'");
// We are a client mode, we need to recreate a TCP connection on the new remote interface
// This is the generic way to accept a redirection
m_redirectInProgress = true;
m_interface->redirectTo(_data.getKey("Location"), true);
return;
}
if (_data.getErrorCode() != enet::HTTPAnswerCode::c101_switchingProtocols) {
ENET_ERROR("change protocol has not been accepted ... " << _data.getErrorCode() << " with message : " << _data.getHelp());
m_interface->stop(true);
@ -444,15 +473,10 @@ bool enet::WebSocket::configHeader(bool _isString, bool _mask) {
m_sendBuffer.clear();
m_sendBuffer.resize(ZEUS_BASE_OFFSET_HEADER, 0);
if (_mask == true) {
std::random_device rd;
// Engine
std::mt19937 e2(rd());
// Distribtuions
std::uniform_real_distribution<> dist(0, 0xFF);
m_dataMask[0] = uint8_t(dist(e2));
m_dataMask[1] = uint8_t(dist(e2));
m_dataMask[2] = uint8_t(dist(e2));
m_dataMask[3] = uint8_t(dist(e2));
m_dataMask[0] = uint8_t(etk::tool::urand(0,255));
m_dataMask[1] = uint8_t(etk::tool::urand(0,255));
m_dataMask[2] = uint8_t(etk::tool::urand(0,255));
m_dataMask[3] = uint8_t(etk::tool::urand(0,255));
}
return true;
}
@ -465,7 +489,7 @@ int32_t enet::WebSocket::writeData(uint8_t* _data, int32_t _len) {
}
int32_t enet::WebSocket::send() {
if (m_interface == nullptr) {
if (m_interface == null) {
ENET_ERROR("Nullptr interface ...");
return -1;
}
@ -514,6 +538,7 @@ int32_t enet::WebSocket::send() {
}
int32_t enet::WebSocket::write(const void* _data, int32_t _len, bool _isString, bool _mask) {
ethread::UniqueLock lock(m_mutex);
if (configHeader(_isString, _mask) == false) {
return -1;
}
@ -522,39 +547,42 @@ int32_t enet::WebSocket::write(const void* _data, int32_t _len, bool _isString,
}
void enet::WebSocket::controlPing() {
if (m_interface == nullptr) {
if (m_interface == null) {
ENET_ERROR("Nullptr interface ...");
return;
}
ethread::UniqueLock lock(m_mutex);
uint8_t header = enet::websocket::FLAG_FIN
| enet::websocket::OPCODE_FRAME_PING;
m_lastSend = std::chrono::steady_clock::now();
m_lastSend = echrono::Steady::now();
m_interface->write(&header, sizeof(uint8_t));
header = 0;
m_interface->write(&header, sizeof(uint8_t));
}
void enet::WebSocket::controlPong() {
if (m_interface == nullptr) {
if (m_interface == null) {
ENET_ERROR("Nullptr interface ...");
return;
}
ethread::UniqueLock lock(m_mutex);
uint8_t header = enet::websocket::FLAG_FIN
| enet::websocket::OPCODE_FRAME_PONG;
m_lastSend = std::chrono::steady_clock::now();
m_lastSend = echrono::Steady::now();
m_interface->write(&header, sizeof(uint8_t));
header = 0;
m_interface->write(&header, sizeof(uint8_t));
}
void enet::WebSocket::controlClose() {
if (m_interface == nullptr) {
if (m_interface == null) {
ENET_ERROR("Nullptr interface ...");
return;
}
ethread::UniqueLock lock(m_mutex);
uint8_t header = enet::websocket::FLAG_FIN
| enet::websocket::OPCODE_FRAME_CLOSE;
m_lastSend = std::chrono::steady_clock::now();
m_lastSend = echrono::Steady::now();
m_interface->write(&header, sizeof(uint8_t));
header = 0;
m_interface->write(&header, sizeof(uint8_t));

View File

@ -1,30 +1,33 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <enet/Http.hpp>
#include <ememory/memory.hpp>
#include <vector>
#include <map>
#include <echrono/Steady.hpp>
#include <etk/Vector.hpp>
#include <etk/Map.hpp>
namespace enet {
class WebSocket {
protected:
std::vector<uint8_t> m_sendBuffer;
etk::Vector<uint8_t> m_sendBuffer;
bool m_connectionValidate;
ememory::SharedPtr<enet::Http> m_interface;
std::vector<uint8_t> m_buffer;
std::string m_checkKey;
std::chrono::steady_clock::time_point m_lastReceive;
std::chrono::steady_clock::time_point m_lastSend;
etk::Vector<uint8_t> m_buffer;
etk::String m_checkKey;
echrono::Steady m_lastReceive;
echrono::Steady m_lastSend;
ethread::Mutex m_mutex;
bool m_redirectInProgress = false;
public:
const std::chrono::steady_clock::time_point& getLastTimeReceive() {
const echrono::Steady& getLastTimeReceive() {
return m_lastReceive;
}
const std::chrono::steady_clock::time_point& getLastTimeSend() {
const echrono::Steady& getLastTimeSend() {
return m_lastSend;
}
public:
@ -32,10 +35,10 @@ namespace enet {
WebSocket(enet::Tcp _connection, bool _isServer=false);
void setInterface(enet::Tcp _connection, bool _isServer=false);
virtual ~WebSocket();
void start(const std::string& _uri="", const std::vector<std::string>& _listProtocols=std::vector<std::string>());
void start(const etk::String& _uri="", const etk::Vector<etk::String>& _listProtocols=etk::Vector<etk::String>());
void stop(bool _inThread=false);
bool isAlive() const {
if (m_interface == nullptr) {
if (m_interface == null) {
return false;
}
return m_interface->isAlive();
@ -44,13 +47,19 @@ namespace enet {
void onReceiveRequest(const enet::HttpRequest& _data);
void onReceiveAnswer(const enet::HttpAnswer& _data);
protected:
std::string m_protocol;
etk::String m_protocol;
public:
void setProtocol(const std::string& _protocol) {
void setProtocol(const etk::String& _protocol) {
m_protocol = _protocol;
}
public:
using Observer = std::function<void(std::vector<uint8_t>&, bool)>; //!< Define an Observer: function pointer
/**
* @brief Get the address of the connection source IP:port or empty string
* @return string with the remote address name.
*/
const etk::String& getRemoteAddress() const;
public:
using Observer = etk::Function<void(etk::Vector<uint8_t>&, bool)>; //!< Define an Observer: function pointer
protected:
Observer m_observer;
public:
@ -61,8 +70,8 @@ namespace enet {
* @param[in] _args Argument optinnal the user want to add.
*/
template<class CLASS_TYPE>
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(std::vector<uint8_t>&, bool)) {
m_observer = [=](std::vector<uint8_t>& _value, bool _isString){
void connect(CLASS_TYPE* _class, void (CLASS_TYPE::*_func)(etk::Vector<uint8_t>&, bool)) {
m_observer = [=](etk::Vector<uint8_t>& _value, bool _isString){
(*_class.*_func)(_value, _isString);
};
}
@ -71,7 +80,15 @@ namespace enet {
}
// Only server:
public:
using ObserverUriCheck = std::function<bool(const std::string&, const std::vector<std::string>&)>; //!< Define an Observer: function pointer
/**
* @brief Define an Observer: function pointer
* @param[in] _uri Current HTTP URI
* @param[in] _protocols List of protocol requested
* @return "OK" Connection accepted ==> send header
* @return "CLOSE" Close the current connection: 404
* @return "REDIRECT:IP:port" Redirect at the specific IP and port
*/
using ObserverUriCheck = etk::Function<etk::String(const etk::String&, const etk::Vector<etk::String>&)>;
protected:
ObserverUriCheck m_observerUriCheck;
public:
@ -82,8 +99,8 @@ namespace enet {
* @param[in] _args Argument optinnal the user want to add.
*/
template<class CLASS_TYPE>
void connectUri(CLASS_TYPE* _class, bool (CLASS_TYPE::*_func)(const std::string&, const std::vector<std::string>&)) {
m_observerUriCheck = [=](const std::string& _value, const std::vector<std::string>& _protocols){
void connectUri(CLASS_TYPE* _class, etk::String (CLASS_TYPE::*_func)(const etk::String&, const etk::Vector<etk::String>&)) {
m_observerUriCheck = [=](const etk::String& _value, const etk::Vector<etk::String>& _protocols){
return (*_class.*_func)(_value, _protocols);
};
}
@ -95,8 +112,20 @@ namespace enet {
bool m_haveMask;
uint8_t m_dataMask[4];
public:
ethread::UniqueLock getScopeLock() {
return etk::move(ethread::UniqueLock(m_mutex));
}
/**
* Compose the local header inside a temporary buffer ==> must lock external to prevent multiple simultaneous access
*/
bool configHeader(bool _isString=false, bool _mask= false);
/**
* CWrite data in a temporary buffer ==> must lock external to prevent multiple simultaneous access
*/
int32_t writeData(uint8_t* _data, int32_t _len);
/**
* Use temporary buffer to send it in the socket ==> must lock external to prevent multiple simultaneous access
*/
int32_t send();
/**
* @brief Write a chunk of data on the socket
@ -104,8 +133,8 @@ namespace enet {
* @param[in] _len Size that must be written socket
* @return >0 byte size on the socket write
* @return -1 an error occured.
* @note: This function is locked ...
*/
//TODO : ...
int32_t write(const void* _data, int32_t _len, bool _isString=false, bool _mask= false);
/**
* @brief Write a chunk of data on the socket
@ -114,7 +143,7 @@ namespace enet {
* @return >0 byte size on the socket write
* @return -1 an error occured.
*/
int32_t write(const std::string& _data, bool _writeBackSlashZero = true) {
int32_t write(const etk::String& _data, bool _writeBackSlashZero = true) {
if (_data.size() == 0) {
return 0;
}
@ -131,7 +160,7 @@ namespace enet {
* @return -1 an error occured.
*/
template <class T>
int32_t write(const std::vector<T>& _data) {
int32_t write(const etk::Vector<T>& _data) {
if (_data.size() == 0) {
return 0;
}

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/debug.hpp>

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <enet/enet.hpp>
#include <enet/debug.hpp>
@ -19,7 +19,7 @@ static bool& getInitSatatus() {
void enet::init(int _argc, const char** _argv) {
for (int32_t iii=0; iii<_argc; ++iii) {
std::string value = _argv[iii];
etk::String value = _argv[iii];
if (etk::start_with(value, "--enet") == true) {
ENET_ERROR("Unknow parameter type: '" << value << "'");
}

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#pragma once

100
enet/pourcentEncoding.cpp Normal file
View File

@ -0,0 +1,100 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <enet/pourcentEncoding.hpp>
#include <enet/debug.hpp>
#include <etk/types.hpp>
#include <etk/String.hpp>
const etk::String hexData = "0123456789ABCDEF";
etk::String enet::pourcentEncode(const etk::String& _data) {
etk::String out;
for (auto &it : _data) {
if ( (it >= 'a' && it <= 'z')
|| (it >= 'A' && it <= 'Z')
|| (it >= '0' && it <= '9')
|| it == '-'
|| it == '_'
|| it == '.'
|| it == '~') {
out += it;
} else {
out += "%";
out += hexData[(uint32_t(it)>>4)&0x0F];
out += hexData[uint32_t(it)&0x0F];
}
}
return out;
}
static int32_t convertStringHexToInt(const char _value) {
if (_value >= 'a' && _value <= 'z') {
return int32_t(_value) - int32_t('a') + 10;
}
if (_value >= 'A' && _value <= 'Z') {
return int32_t(_value) - int32_t('A') + 10;
}
if (_value >= '0' && _value <= '9') {
return int32_t(_value) - int32_t('0');
}
ENET_ERROR("Not a hexadecimal Value: '" << _value << "'");
return 0;
}
etk::String enet::pourcentDecode(const etk::String& _data) {
etk::String out;
for (size_t iii=0; iii<_data.size(); ++iii) {
auto it = _data[iii];
if (it == '%') {
if (iii+2 < _data.size()) {
auto val1 = convertStringHexToInt(_data[iii+1])<<4;
val1 += convertStringHexToInt(_data[iii+2]);
out += char(val1);
iii += 2;
} else {
ENET_ERROR("can not convert pourcent ==> input size error: '" << _data << "'");
return out;
}
} else {
out += it;
}
}
return out;
}
etk::String enet::pourcentUriEncode(const etk::Map<etk::String, etk::String>& _data) {
etk::String out;
for (auto &it: _data) {
if (out.empty() == false) {
out += "&";
}
out += enet::pourcentEncode(it.first);
if (it.second.empty() == false) {
out += "=";
out += enet::pourcentEncode(it.second);
}
}
return out;
}
etk::Map<etk::String, etk::String> enet::pourcentUriDecode(const etk::String& _data) {
etk::Map<etk::String, etk::String> out;
auto listElements = etk::split(_data, '&');
for (auto &it : listElements) {
if (it.size() == 0) {
continue;
}
auto offset = it.find('=');
if (offset == etk::String::npos) {
out.set(enet::pourcentDecode(it), "");
continue;
}
out.set(enet::pourcentDecode(it.extract(0, offset)),
enet::pourcentDecode(it.extract(offset+1, etk::String::npos)));
}
return out;
}

43
enet/pourcentEncoding.hpp Normal file
View File

@ -0,0 +1,43 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/String.hpp>
#include <etk/Map.hpp>
namespace enet {
/**
* @brief Encode a string with transform the unvalid char in %XX.
* @param[in] _data Raw string.
* @return Encoded string.
*/
etk::String pourcentEncode(const etk::String& _data);
/**
* @brief Decode a string with %XX with normal chars.
* @param[in] _data Encoded string.
* @return Raw string.
*/
etk::String pourcentDecode(const etk::String& _data);
/**
* @brief Encode a map of string with %XX and "&" between element and = between key and value.
* @param[in] _data Imput map to encode.
* @return Encoded string.
*/
etk::String pourcentUriEncode(const etk::Map<etk::String, etk::String>& _data);
/**
* @brief Encode a map of string with %XX and "&" between element and = between key and value.
* @param[in] _data Encoded string like AAA=333&RRR=333&RRR
* @return Te decoded map of values.
*/
etk::Map<etk::String, etk::String> pourcentUriDecode(const etk::String& _data);
}

View File

@ -1,13 +0,0 @@
Copyright enet Edouard DUPIN
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
import lutin.debug as debug
import realog.debug as debug
import lutin.tools as tools
@ -13,7 +13,7 @@ def get_desc():
return "e-net TEST test software for enet"
def get_licence():
return "APACHE-2"
return "MPL-2"
def get_compagny_type():
return "com"
@ -28,7 +28,7 @@ def configure(target, my_module):
my_module.add_path(".")
my_module.add_depend([
'enet',
'gtest',
'etest',
'test-debug'
])
my_module.add_src_file([

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
import lutin.debug as debug
import realog.debug as debug
import lutin.tools as tools
@ -13,7 +13,7 @@ def get_desc():
return "e-net TEST test software for enet"
def get_licence():
return "APACHE-2"
return "MPL-2"
def get_compagny_type():
return "com"
@ -28,7 +28,7 @@ def configure(target, my_module):
my_module.add_path(".")
my_module.add_depend([
'enet',
'gtest',
'etest',
'test-debug'
])
my_module.add_src_file([

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
import lutin.debug as debug
import realog.debug as debug
import lutin.tools as tools
@ -13,7 +13,7 @@ def get_desc():
return "e-net TEST test software for enet"
def get_licence():
return "APACHE-2"
return "MPL-2"
def get_compagny_type():
return "com"
@ -28,7 +28,7 @@ def configure(target, my_module):
my_module.add_path(".")
my_module.add_depend([
'enet',
'gtest',
'etest',
'test-debug'
])
my_module.add_src_file([

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
import lutin.debug as debug
import realog.debug as debug
import lutin.tools as tools
@ -13,7 +13,7 @@ def get_desc():
return "e-net TEST test software for enet"
def get_licence():
return "APACHE-2"
return "MPL-2"
def get_compagny_type():
return "com"
@ -28,7 +28,7 @@ def configure(target, my_module):
my_module.add_path(".")
my_module.add_depend([
'enet',
'gtest',
'etest',
'test-debug'
])
my_module.add_src_file([

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
import lutin.debug as debug
import realog.debug as debug
import lutin.tools as tools
@ -13,7 +13,7 @@ def get_desc():
return "e-net TEST test software for enet"
def get_licence():
return "APACHE-2"
return "MPL-2"
def get_compagny_type():
return "com"
@ -28,7 +28,7 @@ def configure(target, my_module):
my_module.add_path(".")
my_module.add_depend([
'enet',
'gtest',
'etest',
'test-debug'
])
my_module.add_src_file([

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
import lutin.debug as debug
import realog.debug as debug
import lutin.tools as tools
@ -13,7 +13,7 @@ def get_desc():
return "e-net TEST test software for enet"
def get_licence():
return "APACHE-2"
return "MPL-2"
def get_compagny_type():
return "com"
@ -28,7 +28,7 @@ def configure(target, my_module):
my_module.add_path(".")
my_module.add_depend([
'enet',
'gtest',
'etest',
'test-debug'
])
my_module.add_src_file([

45
lutin_enet-test.py Normal file
View File

@ -0,0 +1,45 @@
#!/usr/bin/python
import realog.debug as debug
import lutin.tools as tools
def get_type():
return "BINARY"
def get_sub_type():
return "TEST"
def get_desc():
return "e-net TEST basic backend"
def get_licence():
return "MPL-2"
def get_compagny_type():
return "com"
def get_compagny_name():
return "atria-soft"
def get_maintainer():
return "authors.txt"
def configure(target, my_module):
my_module.add_path(".")
my_module.add_depend([
'enet',
'etest',
'test-debug'
])
my_module.add_src_file([
'test/main-test.cpp',
'test/main-unit-pourcentEncoding.cpp'
])
return True

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
import lutin.debug as debug
import realog.debug as debug
import lutin.tools as tools
@ -10,7 +10,7 @@ def get_desc():
return "TCP/UDP/HTTP/FTP interface"
def get_licence():
return "APACHE-2"
return "MPL-2"
def get_compagny_type():
return "com"
@ -42,6 +42,7 @@ def configure(target, my_module):
'enet/Http.cpp',
'enet/Ftp.cpp',
'enet/WebSocket.cpp',
'enet/pourcentEncoding.cpp',
])
my_module.add_header_file([
'enet/enet.hpp',
@ -53,6 +54,7 @@ def configure(target, my_module):
'enet/Http.hpp',
'enet/Ftp.hpp',
'enet/WebSocket.hpp',
'enet/pourcentEncoding.hpp',
])
if "Windows" in target.get_type():
my_module.add_depend("ws2");

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <test-debug/debug.hpp>
@ -15,7 +15,7 @@
namespace appl {
void onReceiveData(std::vector<uint8_t>& _data) {
void onReceiveData(etk::Vector<uint8_t>& _data) {
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
TEST_INFO("data:" << (char*)&_data[0] << "");
}
@ -25,7 +25,7 @@ int main(int _argc, const char *_argv[]) {
etk::init(_argc, _argv);
enet::init(_argc, _argv);
for (int32_t iii=0; iii<_argc ; ++iii) {
std::string data = _argv[iii];
etk::String data = _argv[iii];
if ( data == "-h"
|| data == "--help") {
TEST_PRINT(etk::getApplicationName() << " - help : ");
@ -38,11 +38,11 @@ int main(int _argc, const char *_argv[]) {
TEST_INFO("== Test HTTP client ==");
TEST_INFO("==================================");
// connect on TCP server:
enet::Tcp tcpConnection = std::move(enet::connectTcpClient("127.0.0.1", 12345));
enet::Tcp tcpConnection = etk::move(enet::connectTcpClient("127.0.0.1", 12345));
// TODO : Check if connection is valid ...
// Create a HTTP connection in Client mode
enet::HttpClient connection(std::move(tcpConnection));
enet::HttpClient connection(etk::move(tcpConnection));
// Set callbacks:
connection.connect(appl::onReceiveData);
@ -53,7 +53,7 @@ int main(int _argc, const char *_argv[]) {
connection.setHeader(req);
while (connection.isAlive() == true) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
ethread::sleepMilliSeconds((100));
}
return 0;
}

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <test-debug/debug.hpp>
@ -16,7 +16,7 @@
namespace appl {
void onReceiveData(std::vector<uint8_t>& _data, bool _isString) {
void onReceiveData(etk::Vector<uint8_t>& _data, bool _isString) {
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
if (_isString == true) {
_data.resize(_data.size()+1);
@ -32,7 +32,7 @@ int main(int _argc, const char *_argv[]) {
etk::init(_argc, _argv);
enet::init(_argc, _argv);
for (int32_t iii=0; iii<_argc ; ++iii) {
std::string data = _argv[iii];
etk::String data = _argv[iii];
if ( data == "-h"
|| data == "--help") {
TEST_PRINT(etk::getApplicationName() << " - help : ");
@ -45,19 +45,19 @@ int main(int _argc, const char *_argv[]) {
TEST_INFO("== Test WebSocket client ==");
TEST_INFO("==================================");
// connect on TCP server:
enet::Tcp tcpConnection = std::move(enet::connectTcpClient("127.0.0.1", 12345));
enet::Tcp tcpConnection = etk::move(enet::connectTcpClient("127.0.0.1", 12345));
// TODO : Check if connection is valid ...
// Create a HTTP connection in Client mode
enet::WebSocket connection(std::move(tcpConnection), false);
enet::WebSocket connection(etk::move(tcpConnection), false);
// Set callbacks:
connection.connect(appl::onReceiveData);
// start http connection (the actual state is just TCP start ...)
std::vector<std::string> protocols;
protocols.push_back("test1526/1.0");
protocols.push_back("test1526/1.5");
protocols.push_back("Hello");
etk::Vector<etk::String> protocols;
protocols.pushBack("test1526/1.0");
protocols.pushBack("test1526/1.5");
protocols.pushBack("Hello");
connection.start("/plop.txt", protocols);
// send some data to play ...
@ -66,7 +66,7 @@ int main(int _argc, const char *_argv[]) {
int32_t timeout = 20;
while (connection.isAlive() == true
&& timeout > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
ethread::sleepMilliSeconds((100));
timeout--;
}
return 0;

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <test-debug/debug.hpp>
@ -10,14 +10,13 @@
#include <enet/TcpClient.hpp>
#include <enet/Http.hpp>
#include <etk/etk.hpp>
#include <iostream>
#include <etk/stdTools.hpp>
int main(int _argc, const char *_argv[]) {
etk::init(_argc, _argv);
enet::init(_argc, _argv);
for (int32_t iii=0; iii<_argc ; ++iii) {
std::string data = _argv[iii];
etk::String data = _argv[iii];
if ( data == "-h"
|| data == "--help") {
TEST_PRINT(etk::getApplicationName() << " - help : ");
@ -31,7 +30,7 @@ int main(int _argc, const char *_argv[]) {
TEST_INFO("==================================");
// client mode ...
// connect on TCP server:
enet::Tcp connection = std::move(enet::connectTcpClient("127.0.0.1", 12345));
enet::Tcp connection = etk::move(enet::connectTcpClient("127.0.0.1", 12345));
TEST_INFO("CLIENT connect ...");
if (connection.getConnectionStatus() != enet::Tcp::status::link) {
TEST_ERROR("can not link to the socket...");
@ -45,7 +44,7 @@ int main(int _argc, const char *_argv[]) {
int32_t len = connection.read(data, 1024);
TEST_INFO("read len=" << len << " data='" << data << "'");
//if (data[len-1] == '2') {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
ethread::sleepMilliSeconds((delay));
delay--;
if (delay == 0) {
delay = 500;

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <test-debug/debug.hpp>
@ -14,7 +14,7 @@
#include <etk/stdTools.hpp>
namespace appl {
void onReceiveData(enet::HttpServer* _interface, std::vector<uint8_t>& _data) {
void onReceiveData(enet::HttpServer* _interface, etk::Vector<uint8_t>& _data) {
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
}
void onReceiveHeader(enet::HttpServer* _interface, const enet::HttpRequest& _data) {
@ -23,8 +23,8 @@ namespace appl {
if (_data.getType() == enet::HTTPReqType::HTTP_GET) {
if (_data.getUri() == "plop.txt") {
enet::HttpAnswer answer(enet::HTTPAnswerCode::c200_ok);
std::string data = "<html><head></head></body>coucou</body></html>";
answer.setKey("Content-Length", etk::to_string(data.size()));
etk::String data = "<html><head></head></body>coucou</body></html>";
answer.setKey("Content-Length", etk::toString(data.size()));
_interface->setHeader(answer);
_interface->write(data);
_interface->stop(true);
@ -42,7 +42,7 @@ int main(int _argc, const char *_argv[]) {
etk::init(_argc, _argv);
enet::init(_argc, _argv);
for (int32_t iii=0; iii<_argc ; ++iii) {
std::string data = _argv[iii];
etk::String data = _argv[iii];
if ( data == "-h"
|| data == "--help") {
TEST_PRINT(etk::getApplicationName() << " - help : ");
@ -62,16 +62,16 @@ int main(int _argc, const char *_argv[]) {
// Start listening ...
interface.link();
// Wait a new connection ..
enet::Tcp tcpConnection = std::move(interface.waitNext());
enet::Tcp tcpConnection = etk::move(interface.waitNext());
// Free Connected port
interface.unlink();
// TODO : Check if connection is valid ...
// Create a HTTP connection in Server mode
enet::HttpServer connection(std::move(tcpConnection));
enet::HttpServer connection(etk::move(tcpConnection));
enet::HttpServer* tmp = &connection;
// Set callbacks:
connection.connect([=](std::vector<uint8_t>& _value){
connection.connect([=](etk::Vector<uint8_t>& _value){
appl::onReceiveData(tmp, _value);
});
connection.connectHeader([=](const enet::HttpRequest& _value){
@ -82,7 +82,7 @@ int main(int _argc, const char *_argv[]) {
connection.start();
while (connection.isAlive() == true) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
ethread::sleepMilliSeconds((100));
}
@ -97,8 +97,8 @@ int main(int _argc, const char *_argv[]) {
TEST_INFO("----------------------------");
TEST_INFO("POST data : ");
std::map<std::string, std::string> values;
values.insert(std::make_pair<std::string, std::string>("plop", "valuePlop"));
etk::Map<etk::String, etk::String> values;
values.insert(etk::makePair<etk::String, etk::String>("plop", "valuePlop"));
if (connection.post("", values) == false) {
TEST_ERROR("can not POST data...");
return -1;
@ -107,7 +107,7 @@ int main(int _argc, const char *_argv[]) {
TEST_INFO("----------------------------");
TEST_INFO("POST xml : ");
if (connection.post("", "text/xml; charset=utf-8", "<plop><string>value1</string></plop>") == false) {
if (connection.post("", "text/xml; charset=utf-8", "<plop><etk/String.hpp>value1</string></plop>") == false) {
TEST_ERROR("can not POST XML data...");
return -1;
}

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <test-debug/debug.hpp>
@ -15,7 +15,7 @@
#include <etk/stdTools.hpp>
namespace appl {
void onReceiveData(enet::WebSocket* _interface, std::vector<uint8_t>& _data, bool _isString) {
void onReceiveData(enet::WebSocket* _interface, etk::Vector<uint8_t>& _data, bool _isString) {
TEST_INFO("Receive Datas : " << _data.size() << " bytes");
if (_isString == true) {
_data.resize(_data.size()+1);
@ -26,7 +26,7 @@ namespace appl {
TEST_INFO("binary data: ... ");
}
}
bool onReceiveUri(enet::WebSocket* _interface, const std::string& _uri, const std::vector<std::string>& _protocols) {
bool onReceiveUri(enet::WebSocket* _interface, const etk::String& _uri, const etk::Vector<etk::String>& _protocols) {
TEST_INFO("Receive Header uri: " << _uri);
for (auto &it : _protocols) {
if (it == "test1526/1.5") {
@ -45,7 +45,7 @@ int main(int _argc, const char *_argv[]) {
etk::init(_argc, _argv);
enet::init(_argc, _argv);
for (int32_t iii=0; iii<_argc ; ++iii) {
std::string data = _argv[iii];
etk::String data = _argv[iii];
if ( data == "-h"
|| data == "--help") {
TEST_PRINT(etk::getApplicationName() << " - help : ");
@ -65,19 +65,19 @@ int main(int _argc, const char *_argv[]) {
// Start listening ...
interface.link();
// Wait a new connection ..
enet::Tcp tcpConnection = std::move(interface.waitNext());
enet::Tcp tcpConnection = etk::move(interface.waitNext());
// Free Connected port
interface.unlink();
// TODO : Check if connection is valid ...
// Create a HTTP connection in Server mode
enet::WebSocket connection(std::move(tcpConnection), true);
enet::WebSocket connection(etk::move(tcpConnection), true);
enet::WebSocket* tmp = &connection;
// Set callbacks:
connection.connect([=](std::vector<uint8_t>& _value, bool _isString){
connection.connect([=](etk::Vector<uint8_t>& _value, bool _isString){
appl::onReceiveData(tmp, _value, _isString);
});
connection.connectUri([=](const std::string& _value, const std::vector<std::string>& _protocols){
connection.connectUri([=](const etk::String& _value, const etk::Vector<etk::String>& _protocols){
return appl::onReceiveUri(tmp, _value, _protocols);
});
@ -85,7 +85,7 @@ int main(int _argc, const char *_argv[]) {
connection.start();
while (connection.isAlive() == true) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
ethread::sleepMilliSeconds((100));
}
return 0;
}

View File

@ -1,7 +1,7 @@
/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
* @license MPL v2.0 (see license file)
*/
#include <test-debug/debug.hpp>
@ -17,7 +17,7 @@ int main(int _argc, const char *_argv[]) {
etk::init(_argc, _argv);
enet::init(_argc, _argv);
for (int32_t iii=0; iii<_argc ; ++iii) {
std::string data = _argv[iii];
etk::String data = _argv[iii];
if ( data == "-h"
|| data == "--help") {
TEST_PRINT(etk::getApplicationName() << " - help : ");
@ -37,13 +37,13 @@ int main(int _argc, const char *_argv[]) {
// Start listening ...
interface.link();
// Wait a new connection ..
enet::Tcp tcpConnection = std::move(interface.waitNext());
enet::Tcp tcpConnection = etk::move(interface.waitNext());
// Free Connected port
interface.unlink();
int32_t iii = 0;
while (tcpConnection.getConnectionStatus() == enet::Tcp::status::link) {
int32_t len = tcpConnection.write("plop" + etk::to_string(iii));
int32_t len = tcpConnection.write("plop" + etk::toString(iii));
TEST_INFO("write len=" << len);
char data[1024];
len = tcpConnection.read(data, 1024);

18
test/main-test.cpp Normal file
View File

@ -0,0 +1,18 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <etk/types.hpp>
#include <test-debug/debug.hpp>
#include <etest/etest.hpp>
int main(int argc, const char *argv[]) {
// init test engine:
etest::init(argc, argv);
TEST_INFO("TEST ETK");
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,38 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <etk/types.hpp>
#include <test-debug/debug.hpp>
#include <etest/etest.hpp>
#include <enet/pourcentEncoding.hpp>
TEST(pourcentSerializer, stringEncode) {
EXPECT_EQ(enet::pourcentEncode("hello"), "hello");
EXPECT_EQ(enet::pourcentEncode("hello@plop plouf-_~"), "hello%40plop%20plouf-_~");
}
TEST(pourcentSerializer, stringDecode) {
EXPECT_EQ(enet::pourcentDecode("hello"), "hello");
EXPECT_EQ(enet::pourcentDecode("hello%40plop%20plouf-_~"), "hello@plop plouf-_~");
}
TEST(pourcentSerializer, mapEncode) {
etk::Map<etk::String, etk::String> data;
data.set("hello", "value1");
data.set("simpleKey", "");
data.set("special Key", "coucou");
data.set("email", "you@example.com");
EXPECT_EQ(enet::pourcentUriEncode(data), "email=you%40example.com&hello=value1&simpleKey&special%20Key=coucou");
}
TEST(pourcentSerializer, mapDecode) {
auto data = enet::pourcentUriDecode("hello=value1&simpleKey&special%20Key=coucou&email=you%40example.com");
EXPECT_EQ(data.size(), 4);
EXPECT_EQ(data["hello"], "value1");
EXPECT_EQ(data["simpleKey"], "");
EXPECT_EQ(data["special Key"], "coucou");
EXPECT_EQ(data["email"], "you@example.com");
}

View File

@ -1 +1 @@
0.4.0
1.0.0