1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-11-23 01:49:53 +03:00

Implementation of the JSON-RPC API and the Web Admin interface. (dnobori's internal note: 7579 - 7682)

This commit is contained in:
Daiyuu Nobori 2019-05-28 12:51:51 +09:00
parent 03841e4181
commit 98b08c2ad1
35 changed files with 5991 additions and 231 deletions

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,8 @@ struct ADMIN
LIST *LogFileList; // Accessible log file list LIST *LogFileList; // Accessible log file list
UINT ClientBuild; // Build number of the client UINT ClientBuild; // Build number of the client
RPC_WINVER ClientWinVer; // Windows version of client RPC_WINVER ClientWinVer; // Windows version of client
UINT MaxJsonRpcRecvSize; // Max JSON-RPC Receive Size
char dummy1[MAX_HUBNAME_LEN + 1]; // hubname buffer (dummy)
}; };
// Test // Test
@ -118,7 +120,8 @@ struct RPC_INT
// Set Password // Set Password
struct RPC_SET_PASSWORD struct RPC_SET_PASSWORD
{ {
UCHAR HashedPassword[SHA1_SIZE]; // Hashed password UCHAR HashedPassword[SHA1_SIZE]; // Hashed password (for traditional RPC)
char PlainTextPassword[MAX_SIZE]; // Plaintext password (for JSON-RPC)
}; };
// Server farm configuration * // Server farm configuration *
@ -131,6 +134,7 @@ struct RPC_FARM
char ControllerName[MAX_HOST_NAME_LEN + 1]; // Controller name char ControllerName[MAX_HOST_NAME_LEN + 1]; // Controller name
UINT ControllerPort; // Controller port UINT ControllerPort; // Controller port
UCHAR MemberPassword[SHA1_SIZE]; // Member password UCHAR MemberPassword[SHA1_SIZE]; // Member password
char MemberPasswordPlaintext[MAX_SIZE]; // Member password (plaintext)
UINT Weight; // Performance ratio UINT Weight; // Performance ratio
bool ControllerOnly; // Only controller function bool ControllerOnly; // Only controller function
}; };
@ -236,6 +240,7 @@ struct RPC_CREATE_HUB
char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
UCHAR HashedPassword[SHA1_SIZE]; // Administrative password UCHAR HashedPassword[SHA1_SIZE]; // Administrative password
UCHAR SecurePassword[SHA1_SIZE]; // Administrator password UCHAR SecurePassword[SHA1_SIZE]; // Administrator password
char AdminPasswordPlainText[MAX_SIZE]; // Password (plaintext)
bool Online; // Online flag bool Online; // Online flag
RPC_HUB_OPTION HubOption; // HUB options RPC_HUB_OPTION HubOption; // HUB options
UINT HubType; // Type of HUB UINT HubType; // Type of HUB
@ -553,6 +558,7 @@ struct RPC_ENUM_SESSION_ITEM
char RemoteHostname[MAX_HOST_NAME_LEN + 1]; // Remote server name char RemoteHostname[MAX_HOST_NAME_LEN + 1]; // Remote server name
char Username[MAX_USERNAME_LEN + 1]; // User name char Username[MAX_USERNAME_LEN + 1]; // User name
UINT Ip; // IP address (IPv4) UINT Ip; // IP address (IPv4)
IP ClientIP; // IP address (IPv4 / IPv6)
char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
UINT MaxNumTcp; // Maximum number of TCP connections UINT MaxNumTcp; // Maximum number of TCP connections
UINT CurrentNumTcp; // Number of currentl TCP connections UINT CurrentNumTcp; // Number of currentl TCP connections
@ -569,6 +575,8 @@ struct RPC_ENUM_SESSION_ITEM
bool IsDormantEnabled; // Is the dormant state enabled bool IsDormantEnabled; // Is the dormant state enabled
bool IsDormant; // Is in the dormant state bool IsDormant; // Is in the dormant state
UINT64 LastCommDormant; // Last comm interval in the dormant state UINT64 LastCommDormant; // Last comm interval in the dormant state
UINT64 CreatedTime; // Creation date and time
UINT64 LastCommTime; // Last communication date and time
}; };
// Disconnect the session // Disconnect the session
@ -605,8 +613,9 @@ struct RPC_ENUM_IP_TABLE_ITEM
{ {
UINT Key; // Key UINT Key; // Key
char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
UINT Ip; // IP address UINT Ip; // IPv4 address
IP IpV6; // IPv6 address IP IpV6; // IPv6 address
IP IpAddress; // IPv4 / IPv6 Address
bool DhcpAllocated; // Assigned by the DHCP bool DhcpAllocated; // Assigned by the DHCP
UINT64 CreatedTime; // Creation date and time UINT64 CreatedTime; // Creation date and time
UINT64 UpdatedTime; // Updating date UINT64 UpdatedTime; // Updating date
@ -892,6 +901,10 @@ struct RPC_AZURE_STATUS
bool IsConnected; // Whether it's connected bool IsConnected; // Whether it's connected
}; };
// Constants
#define ADMIN_RPC_MAX_POST_SIZE_BY_SERVER_ADMIN MAX_PACK_SIZE
#define ADMIN_RPC_MAX_POST_SIZE_BY_HUB_ADMIN (8 * 1024 * 1024)
// Function prototype // Function prototype
UINT AdminAccept(CONNECTION *c, PACK *p); UINT AdminAccept(CONNECTION *c, PACK *p);
@ -916,6 +929,26 @@ BUF *DownloadFileFromServer(RPC *r, char *server_name, char *filepath, UINT tota
bool CheckAdminSourceAddress(SOCK *sock, char *hubname); bool CheckAdminSourceAddress(SOCK *sock, char *hubname);
void SiEnumSessionMain(SERVER *s, RPC_ENUM_SESSION *t); void SiEnumSessionMain(SERVER *s, RPC_ENUM_SESSION *t);
bool SiIsEmptyPassword(void *hash_password); bool SiIsEmptyPassword(void *hash_password);
void JsonRpcProcPost(CONNECTION *c, SOCK *s, HTTP_HEADER *h, UINT post_data_size);
void JsonRpcProcGet(CONNECTION *c, SOCK *s, HTTP_HEADER *h, char *url_target);
void JsonRpcProcOptions(CONNECTION *c, SOCK *s, HTTP_HEADER *h, char *url_target);
JSON_VALUE *JsonRpcProcRequestObject(ADMIN *admin, CONNECTION *c, SOCK *s, JSON_VALUE *json_req, char *method_name);
JSON_VALUE *JsonRpcNewError(int code, wchar_t *message);
JSON_VALUE *JsonRpcNewResponse(PACK *p);
bool HttpParseBasicAuthHeader(HTTP_HEADER *h, char *username, UINT username_size, char *password, UINT password_size);
ADMIN *JsonRpcAuthLogin(CEDAR *c, SOCK *sock, HTTP_HEADER *h);
JSON_VALUE *QueryStringToJsonListValue(char *qs);
JSON_VALUE *ConstructDummyJsonRpcRequest(char *method_name, JSON_VALUE *p);
void AdminWebProcPost(CONNECTION *c, SOCK *s, HTTP_HEADER *h, UINT post_data_size, char *url_target);
void AdminWebProcGet(CONNECTION *c, SOCK *s, HTTP_HEADER *h, char *url_target);
bool AdminWebHandleFileRequest(ADMIN *a, CONNECTION *c, SOCK *s, HTTP_HEADER *h, char *url_src, char *query_string, char *virtual_root_dir, char *physical_root_dir);
BUF *AdminWebProcessServerSideInclude(BUF *src_txt, char *filename, UINT depth);
bool AdminWebSendBody(SOCK *s, UINT status_code, char *status_string, UCHAR *data, UINT data_size, char *content_type, char *add_header_name, char *add_header_value, HTTP_HEADER *request_headers);
bool AdminWebSend404Error(SOCK *s, HTTP_HEADER *request_headers);
bool AdminWebSend302Redirect(SOCK *s, char *url, char *query_string, HTTP_HEADER *request_headers);
BUF *AdminWebTryFindAndReadFile(char *vroot, char *proot, char *url, char *ret_filename, UINT ret_filename_size, bool *is_index_html);
BUF *AdminWebTryOneFile(char *filename, char *ret_filename, UINT ret_filename_size);
bool AdminWebSendUnauthorized(SOCK *s, HTTP_HEADER *http_request_headers);
UINT StTest(ADMIN *a, RPC_TEST *t); UINT StTest(ADMIN *a, RPC_TEST *t);
UINT StGetServerInfo(ADMIN *a, RPC_SERVER_INFO *t); UINT StGetServerInfo(ADMIN *a, RPC_SERVER_INFO *t);
@ -1291,7 +1324,7 @@ void OutRpcAccess(PACK *p, ACCESS *a);
void InRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a, PACK *p); void InRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a, PACK *p);
void OutRpcEnumAccessList(PACK *p, RPC_ENUM_ACCESS_LIST *a); void OutRpcEnumAccessList(PACK *p, RPC_ENUM_ACCESS_LIST *a);
void FreeRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a); void FreeRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a);
void *InRpcAuthData(PACK *p, UINT *authtype); void *InRpcAuthData(PACK *p, UINT *authtype, char *username);
void OutRpcAuthData(PACK *p, void *authdata, UINT authtype); void OutRpcAuthData(PACK *p, void *authdata, UINT authtype);
void FreeRpcAuthData(void *authdata, UINT authtype); void FreeRpcAuthData(void *authdata, UINT authtype);
void InRpcSetUser(RPC_SET_USER *t, PACK *p); void InRpcSetUser(RPC_SET_USER *t, PACK *p);

View File

@ -9578,8 +9578,9 @@ void CmPrintStatusToListViewEx(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool
GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL); GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL);
LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_START_TIME"), tmp); LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_START_TIME"), tmp);
GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablishedTime), NULL); GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablisiedTime), NULL);
LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablishedTime == 0 ? _UU("CM_ST_NONE") : tmp); /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablisiedTime == 0 ? _UU("CM_ST_NONE") : tmp);
if (s->Connected) if (s->Connected)
{ {

View File

@ -137,6 +137,7 @@ typedef struct BLACK BLACK;
typedef struct SEND_SIGNATURE_PARAM SEND_SIGNATURE_PARAM; typedef struct SEND_SIGNATURE_PARAM SEND_SIGNATURE_PARAM;
typedef struct UPDATE_CLIENT UPDATE_CLIENT; typedef struct UPDATE_CLIENT UPDATE_CLIENT;
typedef struct UPDATE_CLIENT_SETTING UPDATE_CLIENT_SETTING; typedef struct UPDATE_CLIENT_SETTING UPDATE_CLIENT_SETTING;
typedef struct HTTP_MIME_TYPE HTTP_MIME_TYPE;
// ============================================================== // ==============================================================

View File

@ -3810,14 +3810,16 @@ void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e)
PackAddNum(p, "NumItem", e->NumItem); PackAddNum(p, "NumItem", e->NumItem);
PackSetCurrentJsonGroupName(p, "CAList");
for (i = 0;i < e->NumItem;i++) for (i = 0;i < e->NumItem;i++)
{ {
RPC_CLIENT_ENUM_CA_ITEM *item = e->Items[i]; RPC_CLIENT_ENUM_CA_ITEM *item = e->Items[i];
PackAddIntEx(p, "Key", item->Key, i, e->NumItem); PackAddIntEx(p, "Key", item->Key, i, e->NumItem);
PackAddUniStrEx(p, "SubjectName", item->SubjectName, i, e->NumItem); PackAddUniStrEx(p, "SubjectName", item->SubjectName, i, e->NumItem);
PackAddUniStrEx(p, "IssuerName", item->IssuerName, i, e->NumItem); PackAddUniStrEx(p, "IssuerName", item->IssuerName, i, e->NumItem);
PackAddInt64Ex(p, "Expires", item->Expires, i, e->NumItem); PackAddTime64Ex(p, "Expires", item->Expires, i, e->NumItem);
} }
PackSetCurrentJsonGroupName(p, NULL);
} }
// RPC_GET_ISSUER // RPC_GET_ISSUER
@ -4088,6 +4090,7 @@ void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e)
PackAddNum(p, "NumItem", e->NumItem); PackAddNum(p, "NumItem", e->NumItem);
PackSetCurrentJsonGroupName(p, "SecureDeviceList");
for (i = 0;i < e->NumItem;i++) for (i = 0;i < e->NumItem;i++)
{ {
RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i]; RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i];
@ -4097,6 +4100,7 @@ void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e)
PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem); PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);
PackAddStrEx(p, "Manufacturer", item->Manufacturer, i, e->NumItem); PackAddStrEx(p, "Manufacturer", item->Manufacturer, i, e->NumItem);
} }
PackSetCurrentJsonGroupName(p, NULL);
} }
// RPC_USE_SECURE // RPC_USE_SECURE
@ -4153,11 +4157,13 @@ void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e)
PackAddNum(p, "NumItem", e->NumItem); PackAddNum(p, "NumItem", e->NumItem);
PackAddInt(p, "hWnd", e->hWnd); PackAddInt(p, "hWnd", e->hWnd);
PackSetCurrentJsonGroupName(p, "ObjectList");
for (i = 0;i < e->NumItem;i++) for (i = 0;i < e->NumItem;i++)
{ {
PackAddStrEx(p, "ItemName", e->ItemName[i], i, e->NumItem); PackAddStrEx(p, "ItemName", e->ItemName[i], i, e->NumItem);
PackAddIntEx(p, "ItemType", e->ItemType[i], i, e->NumItem); PackAddIntEx(p, "ItemType", e->ItemType[i], i, e->NumItem);
} }
PackSetCurrentJsonGroupName(p, NULL);
} }
// RPC_CLIENT_CREATE_VLAN // RPC_CLIENT_CREATE_VLAN
@ -4277,6 +4283,7 @@ void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v)
PackAddNum(p, "NumItem", v->NumItem); PackAddNum(p, "NumItem", v->NumItem);
PackSetCurrentJsonGroupName(p, "VLanList");
for (i = 0;i < v->NumItem;i++) for (i = 0;i < v->NumItem;i++)
{ {
RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i]; RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i];
@ -4286,6 +4293,7 @@ void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v)
PackAddStrEx(p, "MacAddress", item->MacAddress, i, v->NumItem); PackAddStrEx(p, "MacAddress", item->MacAddress, i, v->NumItem);
PackAddStrEx(p, "Version", item->Version, i, v->NumItem); PackAddStrEx(p, "Version", item->Version, i, v->NumItem);
} }
PackSetCurrentJsonGroupName(p, NULL);
} }
// CLIENT_OPTION // CLIENT_OPTION
@ -4352,10 +4360,10 @@ void OutRpcClientOption(PACK *p, CLIENT_OPTION *c)
PackAddInt(p, "NumRetry", c->NumRetry); PackAddInt(p, "NumRetry", c->NumRetry);
PackAddInt(p, "RetryInterval", c->RetryInterval); PackAddInt(p, "RetryInterval", c->RetryInterval);
PackAddInt(p, "MaxConnection", c->MaxConnection); PackAddInt(p, "MaxConnection", c->MaxConnection);
PackAddInt(p, "UseEncrypt", c->UseEncrypt); PackAddBool(p, "UseEncrypt", c->UseEncrypt);
PackAddInt(p, "UseCompress", c->UseCompress); PackAddBool(p, "UseCompress", c->UseCompress);
PackAddInt(p, "HalfConnection", c->HalfConnection); PackAddBool(p, "HalfConnection", c->HalfConnection);
PackAddInt(p, "NoRoutingTracking", c->NoRoutingTracking); PackAddBool(p, "NoRoutingTracking", c->NoRoutingTracking);
PackAddInt(p, "AdditionalConnectionInterval", c->AdditionalConnectionInterval); PackAddInt(p, "AdditionalConnectionInterval", c->AdditionalConnectionInterval);
PackAddInt(p, "ConnectionDisconnectSpan", c->ConnectionDisconnectSpan); PackAddInt(p, "ConnectionDisconnectSpan", c->ConnectionDisconnectSpan);
PackAddBool(p, "HideStatusWindow", c->HideStatusWindow); PackAddBool(p, "HideStatusWindow", c->HideStatusWindow);
@ -4568,6 +4576,7 @@ void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e)
PackAddNum(p, "NumItem", e->NumItem); PackAddNum(p, "NumItem", e->NumItem);
PackSetCurrentJsonGroupName(p, "AccountList");
for (i = 0;i < e->NumItem;i++) for (i = 0;i < e->NumItem;i++)
{ {
RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i]; RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i];
@ -4583,10 +4592,11 @@ void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e)
PackAddBoolEx(p, "Connected", item->Connected, i, e->NumItem); PackAddBoolEx(p, "Connected", item->Connected, i, e->NumItem);
PackAddIntEx(p, "Port", item->Port, i, e->NumItem); PackAddIntEx(p, "Port", item->Port, i, e->NumItem);
PackAddStrEx(p, "HubName", item->HubName, i, e->NumItem); PackAddStrEx(p, "HubName", item->HubName, i, e->NumItem);
PackAddInt64Ex(p, "CreateDateTime", item->CreateDateTime, i, e->NumItem); PackAddTime64Ex(p, "CreateDateTime", item->CreateDateTime, i, e->NumItem);
PackAddInt64Ex(p, "UpdateDateTime", item->UpdateDateTime, i, e->NumItem); PackAddTime64Ex(p, "UpdateDateTime", item->UpdateDateTime, i, e->NumItem);
PackAddInt64Ex(p, "LastConnectDateTime", item->LastConnectDateTime, i, e->NumItem); PackAddTime64Ex(p, "LastConnectDateTime", item->LastConnectDateTime, i, e->NumItem);
} }
PackSetCurrentJsonGroupName(p, NULL);
} }
// RPC_CLIENT_DELETE_ACCOUNT // RPC_CLIENT_DELETE_ACCOUNT
@ -4702,9 +4712,9 @@ void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c)
PackAddData(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE); PackAddData(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);
PackAddInt64(p, "CreateDateTime", c->CreateDateTime); PackAddTime64(p, "CreateDateTime", c->CreateDateTime);
PackAddInt64(p, "UpdateDateTime", c->UpdateDateTime); PackAddTime64(p, "UpdateDateTime", c->UpdateDateTime);
PackAddInt64(p, "LastConnectDateTime", c->LastConnectDateTime); PackAddTime64(p, "LastConnectDateTime", c->LastConnectDateTime);
} }
// RPC_CLIENT_CONNECT // RPC_CLIENT_CONNECT
@ -4792,7 +4802,8 @@ void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p
s->NumTcpConnectionsDownload = PackGetInt(p, "NumTcpConnectionsDownload"); s->NumTcpConnectionsDownload = PackGetInt(p, "NumTcpConnectionsDownload");
s->StartTime = PackGetInt64(p, "StartTime"); s->StartTime = PackGetInt64(p, "StartTime");
s->FirstConnectionEstablishedTime = PackGetInt64(p, "FirstConnectionEstablishedTime"); /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
s->FirstConnectionEstablisiedTime = PackGetInt64(p, "FirstConnectionEstablisiedTime");
s->CurrentConnectionEstablishTime = PackGetInt64(p, "CurrentConnectionEstablishTime"); s->CurrentConnectionEstablishTime = PackGetInt64(p, "CurrentConnectionEstablishTime");
s->TotalSendSize = PackGetInt64(p, "TotalSendSize"); s->TotalSendSize = PackGetInt64(p, "TotalSendSize");
s->TotalRecvSize = PackGetInt64(p, "TotalRecvSize"); s->TotalRecvSize = PackGetInt64(p, "TotalRecvSize");
@ -4852,32 +4863,32 @@ void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *
PackAddData(p, "SessionKey", c->SessionKey, SHA1_SIZE); PackAddData(p, "SessionKey", c->SessionKey, SHA1_SIZE);
PackAddInt(p, "Active", c->Active); PackAddBool(p, "Active", c->Active);
PackAddInt(p, "Connected", c->Connected); PackAddBool(p, "Connected", c->Connected);
PackAddInt(p, "SessionStatus", c->SessionStatus); PackAddInt(p, "SessionStatus", c->SessionStatus);
PackAddInt(p, "ServerPort", c->ServerPort); PackAddInt(p, "ServerPort", c->ServerPort);
PackAddInt(p, "ServerProductVer", c->ServerProductVer); PackAddInt(p, "ServerProductVer", c->ServerProductVer);
PackAddInt(p, "ServerProductBuild", c->ServerProductBuild); PackAddInt(p, "ServerProductBuild", c->ServerProductBuild);
PackAddInt(p, "NumConnectionsEstablished", c->NumConnectionsEstablished); PackAddInt(p, "NumConnectionsEstablished", c->NumConnectionsEstablished);
PackAddInt(p, "HalfConnection", c->HalfConnection); PackAddBool(p, "HalfConnection", c->HalfConnection);
PackAddInt(p, "QoS", c->QoS); PackAddBool(p, "QoS", c->QoS);
PackAddInt(p, "MaxTcpConnections", c->MaxTcpConnections); PackAddInt(p, "MaxTcpConnections", c->MaxTcpConnections);
PackAddInt(p, "NumTcpConnections", c->NumTcpConnections); PackAddInt(p, "NumTcpConnections", c->NumTcpConnections);
PackAddInt(p, "NumTcpConnectionsUpload", c->NumTcpConnectionsUpload); PackAddInt(p, "NumTcpConnectionsUpload", c->NumTcpConnectionsUpload);
PackAddInt(p, "NumTcpConnectionsDownload", c->NumTcpConnectionsDownload); PackAddInt(p, "NumTcpConnectionsDownload", c->NumTcpConnectionsDownload);
PackAddInt(p, "UseEncrypt", c->UseEncrypt); PackAddBool(p, "UseEncrypt", c->UseEncrypt);
PackAddInt(p, "UseCompress", c->UseCompress); PackAddBool(p, "UseCompress", c->UseCompress);
PackAddInt(p, "IsRUDPSession", c->IsRUDPSession); PackAddBool(p, "IsRUDPSession", c->IsRUDPSession);
PackAddStr(p, "UnderlayProtocol", c->UnderlayProtocol); PackAddStr(p, "UnderlayProtocol", c->UnderlayProtocol);
PackAddInt(p, "IsUdpAccelerationEnabled", c->IsUdpAccelerationEnabled); PackAddBool(p, "IsUdpAccelerationEnabled", c->IsUdpAccelerationEnabled);
PackAddInt(p, "IsUsingUdpAcceleration", c->IsUsingUdpAcceleration); PackAddBool(p, "IsUsingUdpAcceleration", c->IsUsingUdpAcceleration);
PackAddBool(p, "IsBridgeMode", c->IsBridgeMode); PackAddBool(p, "IsBridgeMode", c->IsBridgeMode);
PackAddBool(p, "IsMonitorMode", c->IsMonitorMode); PackAddBool(p, "IsMonitorMode", c->IsMonitorMode);
PackAddInt64(p, "StartTime", c->StartTime); PackAddTime64(p, "StartTime", c->StartTime);
PackAddInt64(p, "FirstConnectionEstablishedTime", c->FirstConnectionEstablishedTime); PackAddTime64(p, "FirstConnectionEstablisiedTime", c->FirstConnectionEstablisiedTime);
PackAddInt64(p, "CurrentConnectionEstablishTime", c->CurrentConnectionEstablishTime); PackAddTime64(p, "CurrentConnectionEstablishTime", c->CurrentConnectionEstablishTime);
PackAddInt64(p, "TotalSendSize", c->TotalSendSize); PackAddInt64(p, "TotalSendSize", c->TotalSendSize);
PackAddInt64(p, "TotalRecvSize", c->TotalRecvSize); PackAddInt64(p, "TotalRecvSize", c->TotalRecvSize);
PackAddInt64(p, "TotalSendSizeReal", c->TotalSendSizeReal); PackAddInt64(p, "TotalSendSizeReal", c->TotalSendSizeReal);
@ -5852,7 +5863,8 @@ void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s)
// Connection start time // Connection start time
st->StartTime = TickToTime(s->CreatedTime); st->StartTime = TickToTime(s->CreatedTime);
// Connection completion time of the first connection // Connection completion time of the first connection
st->FirstConnectionEstablishedTime = TickToTime(s->FirstConnectionEstablishedTime); /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
st->FirstConnectionEstablisiedTime = TickToTime(s->FirstConnectionEstablisiedTime);
// Number of connections have been established so far // Number of connections have been established so far
st->NumConnectionsEstablished = s->NumConnectionsEstablished; st->NumConnectionsEstablished = s->NumConnectionsEstablished;
} }

View File

@ -325,7 +325,8 @@ struct RPC_CLIENT_GET_CONNECTION_STATUS
X *ServerX; // Server certificate X *ServerX; // Server certificate
X *ClientX; // Client certificate X *ClientX; // Client certificate
UINT64 StartTime; // Connection start time UINT64 StartTime; // Connection start time
UINT64 FirstConnectionEstablishedTime; // Connection completion time of the first connection /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
UINT64 FirstConnectionEstablisiedTime; // Connection completion time of the first connection
UINT64 CurrentConnectionEstablishTime; // Connection completion time of this connection UINT64 CurrentConnectionEstablishTime; // Connection completion time of this connection
UINT NumConnectionsEstablished; // Number of connections have been established so far UINT NumConnectionsEstablished; // Number of connections have been established so far
bool HalfConnection; // Half-connection bool HalfConnection; // Half-connection

View File

@ -15077,8 +15077,10 @@ void CmdPrintStatusToListViewEx(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s, boo
GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL); GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL);
CtInsert(ct, _UU("CM_ST_START_TIME"), tmp); CtInsert(ct, _UU("CM_ST_START_TIME"), tmp);
GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablishedTime), NULL); /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
CtInsert(ct, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablishedTime == 0 ? _UU("CM_ST_NONE") : tmp); GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablisiedTime), NULL);
/* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
CtInsert(ct, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablisiedTime == 0 ? _UU("CM_ST_NONE") : tmp);
if (s->Connected) if (s->Connected)
{ {

View File

@ -216,6 +216,9 @@ struct CONNECTION
UINT LastPacketQueueSize; // The last queue size of packets UINT LastPacketQueueSize; // The last queue size of packets
UINT LastRecvFifoTotalSize; // The last RecvFifo total size UINT LastRecvFifoTotalSize; // The last RecvFifo total size
UINT LastRecvBlocksNum; // The last ReceivedBlocks num UINT LastRecvBlocksNum; // The last ReceivedBlocks num
bool IsJsonRpc; // Is JSON-RPC
bool JsonRpcAuthed; // JSON-RPC Authed
LISTENER *Listener; // Listener ref
}; };

View File

@ -37,6 +37,9 @@ void DCGetStatus(DDNS_CLIENT *c, DDNS_CLIENT_STATUS *st)
Copy(&st->InternetSetting, &c->InternetSetting, sizeof(INTERNET_SETTING)); Copy(&st->InternetSetting, &c->InternetSetting, sizeof(INTERNET_SETTING));
} }
Unlock(c->Lock); Unlock(c->Lock);
UniStrCpy(st->ErrStr_IPv4, sizeof(st->ErrStr_IPv4), _E(st->Err_IPv4));
UniStrCpy(st->ErrStr_IPv6, sizeof(st->ErrStr_IPv6), _E(st->Err_IPv6));
} }
// Set the Internet settings // Set the Internet settings

View File

@ -111,6 +111,8 @@ struct DDNS_REGISTER_PARAM
struct DDNS_CLIENT_STATUS struct DDNS_CLIENT_STATUS
{ {
UINT Err_IPv4, Err_IPv6; // Last error UINT Err_IPv4, Err_IPv6; // Last error
wchar_t ErrStr_IPv4[MAX_SIZE];
wchar_t ErrStr_IPv6[MAX_SIZE];
char CurrentHostName[DDNS_MAX_HOSTNAME + 1]; // Current host name char CurrentHostName[DDNS_MAX_HOSTNAME + 1]; // Current host name
char CurrentFqdn[MAX_SIZE]; // Current FQDN char CurrentFqdn[MAX_SIZE]; // Current FQDN
char DnsSuffix[MAX_SIZE]; // DNS suffix char DnsSuffix[MAX_SIZE]; // DNS suffix

View File

@ -558,6 +558,7 @@ void OutRpcEnumDevice(PACK *p, RPC_ENUM_DEVICE *t)
PackAddInt(p, "NumItem", t->NumItem); PackAddInt(p, "NumItem", t->NumItem);
PackSetCurrentJsonGroupName(p, "DeviceList");
for (i = 0;i < t->NumItem;i++) for (i = 0;i < t->NumItem;i++)
{ {
RPC_ENUM_DEVICE_ITEM *d = &t->Items[i]; RPC_ENUM_DEVICE_ITEM *d = &t->Items[i];
@ -565,6 +566,7 @@ void OutRpcEnumDevice(PACK *p, RPC_ENUM_DEVICE *t)
PackAddStrEx(p, "DeviceName", d->DeviceName, i, t->NumItem); PackAddStrEx(p, "DeviceName", d->DeviceName, i, t->NumItem);
PackAddBoolEx(p, "Active", d->Active, i, t->NumItem); PackAddBoolEx(p, "Active", d->Active, i, t->NumItem);
} }
PackSetCurrentJsonGroupName(p, NULL);
PackAddBool(p, "IsLicenseSupported", t->IsLicenseSupported); PackAddBool(p, "IsLicenseSupported", t->IsLicenseSupported);
} }
@ -605,7 +607,7 @@ void OutRpcElLicenseStatus(PACK *p, RPC_EL_LICENSE_STATUS *t)
PackAddBool(p, "Valid", t->Valid); PackAddBool(p, "Valid", t->Valid);
PackAddInt64(p, "SystemId", t->SystemId); PackAddInt64(p, "SystemId", t->SystemId);
PackAddInt64(p, "SystemExpires", t->SystemExpires); PackAddTime64(p, "SystemExpires", t->SystemExpires);
} }
// Listener thread // Listener thread

View File

@ -681,6 +681,8 @@ void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name)
{ {
ADMIN_OPTION *a = LIST_DATA(aol, i); ADMIN_OPTION *a = LIST_DATA(aol, i);
UniStrCpy(a->Descrption, sizeof(a->Descrption), GetHubAdminOptionHelpString(a->Name));
Copy(&ao->Items[i], a, sizeof(ADMIN_OPTION)); Copy(&ao->Items[i], a, sizeof(ADMIN_OPTION));
Free(a); Free(a);

View File

@ -287,6 +287,7 @@ struct ADMIN_OPTION
{ {
char Name[MAX_ADMIN_OPTION_NAME_LEN + 1]; // Name char Name[MAX_ADMIN_OPTION_NAME_LEN + 1]; // Name
UINT Value; // Data UINT Value; // Data
wchar_t Descrption[MAX_SIZE]; // Descrption
}; };
// Certificate Revocation List entry // Certificate Revocation List entry

View File

@ -150,6 +150,9 @@ void TCPAcceptedThread(THREAD *t, void *param)
// Create a connection // Create a connection
c = NewServerConnection(r->Cedar, s, t); c = NewServerConnection(r->Cedar, s, t);
AddRef(r->ref);
c->Listener = r;
// Register to Cedar as a transient connection // Register to Cedar as a transient connection
AddConnection(c->Cedar, c); AddConnection(c->Cedar, c);
@ -169,6 +172,8 @@ void TCPAcceptedThread(THREAD *t, void *param)
// Release // Release
SLog(r->Cedar, "LS_CONNECTION_END_1", c->Name); SLog(r->Cedar, "LS_CONNECTION_END_1", c->Name);
ReleaseListener(c->Listener);
c->Listener = NULL;
ReleaseConnection(c); ReleaseConnection(c);
// Release // Release

View File

@ -797,18 +797,20 @@ void OutRpcEnumDhcp(PACK *p, RPC_ENUM_DHCP *t)
PackAddInt(p, "NumItem", t->NumItem); PackAddInt(p, "NumItem", t->NumItem);
PackAddStr(p, "HubName", t->HubName); PackAddStr(p, "HubName", t->HubName);
PackSetCurrentJsonGroupName(p, "DhcpTable");
for (i = 0;i < t->NumItem;i++) for (i = 0;i < t->NumItem;i++)
{ {
RPC_ENUM_DHCP_ITEM *e = &t->Items[i]; RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
PackAddIntEx(p, "Id", e->Id, i, t->NumItem); PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
PackAddInt64Ex(p, "LeasedTime", e->LeasedTime, i, t->NumItem); PackAddTime64Ex(p, "LeasedTime", e->LeasedTime, i, t->NumItem);
PackAddInt64Ex(p, "ExpireTime", e->ExpireTime, i, t->NumItem); PackAddTime64Ex(p, "ExpireTime", e->ExpireTime, i, t->NumItem);
PackAddDataEx(p, "MacAddress", e->MacAddress, 6, i, t->NumItem); PackAddDataEx(p, "MacAddress", e->MacAddress, 6, i, t->NumItem);
PackAddIp32Ex(p, "IpAddress", e->IpAddress, i, t->NumItem); PackAddIp32Ex(p, "IpAddress", e->IpAddress, i, t->NumItem);
PackAddIntEx(p, "Mask", e->Mask, i, t->NumItem); PackAddIntEx(p, "Mask", e->Mask, i, t->NumItem);
PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumItem); PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumItem);
} }
PackSetCurrentJsonGroupName(p, NULL);
} }
void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t) void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t)
{ {
@ -865,6 +867,8 @@ void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t)
PackAddInt(p, "NumItem", t->NumItem); PackAddInt(p, "NumItem", t->NumItem);
PackAddStr(p, "HubName", t->HubName); PackAddStr(p, "HubName", t->HubName);
PackSetCurrentJsonGroupName(p, "NatTable");
for (i = 0;i < t->NumItem;i++) for (i = 0;i < t->NumItem;i++)
{ {
RPC_ENUM_NAT_ITEM *e = &t->Items[i]; RPC_ENUM_NAT_ITEM *e = &t->Items[i];
@ -877,12 +881,13 @@ void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t)
PackAddIp32Ex(p, "DestIp", e->DestIp, i, t->NumItem); PackAddIp32Ex(p, "DestIp", e->DestIp, i, t->NumItem);
PackAddStrEx(p, "DestHost", e->DestHost, i, t->NumItem); PackAddStrEx(p, "DestHost", e->DestHost, i, t->NumItem);
PackAddIntEx(p, "DestPort", e->DestPort, i, t->NumItem); PackAddIntEx(p, "DestPort", e->DestPort, i, t->NumItem);
PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumItem); PackAddTime64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumItem);
PackAddInt64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumItem); PackAddTime64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumItem);
PackAddInt64Ex(p, "SendSize", e->SendSize, i, t->NumItem); PackAddInt64Ex(p, "SendSize", e->SendSize, i, t->NumItem);
PackAddInt64Ex(p, "RecvSize", e->RecvSize, i, t->NumItem); PackAddInt64Ex(p, "RecvSize", e->RecvSize, i, t->NumItem);
PackAddIntEx(p, "TcpStatus", e->TcpStatus, i, t->NumItem); PackAddIntEx(p, "TcpStatus", e->TcpStatus, i, t->NumItem);
} }
PackSetCurrentJsonGroupName(p, NULL);
} }
void FreeRpcEnumNat(RPC_ENUM_NAT *t) void FreeRpcEnumNat(RPC_ENUM_NAT *t)
{ {

View File

@ -9,6 +9,726 @@
static UCHAR ssl_packet_start[3] = {0x17, 0x03, 0x00}; static UCHAR ssl_packet_start[3] = {0x17, 0x03, 0x00};
// MIME list from https://www.freeformatter.com/mime-types-list.html
static HTTP_MIME_TYPE http_mime_types[] =
{
{".x3d", "application/vnd.hzn-3d-crossword"},
{".3gp", "video/3gpp"},
{".3g2", "video/3gpp2"},
{".mseq", "application/vnd.mseq"},
{".pwn", "application/vnd.3m.post-it-notes"},
{".plb", "application/vnd.3gpp.pic-bw-large"},
{".psb", "application/vnd.3gpp.pic-bw-small"},
{".pvb", "application/vnd.3gpp.pic-bw-var"},
{".tcap", "application/vnd.3gpp2.tcap"},
{".7z", "application/x-7z-compressed"},
{".abw", "application/x-abiword"},
{".ace", "application/x-ace-compressed"},
{".acc", "application/vnd.americandynamics.acc"},
{".acu", "application/vnd.acucobol"},
{".atc", "application/vnd.acucorp"},
{".adp", "audio/adpcm"},
{".aab", "application/x-authorware-bin"},
{".aam", "application/x-authorware-map"},
{".aas", "application/x-authorware-seg"},
{".air", "application/vnd.adobe.air-application-installer-package+zip"},
{".swf", "application/x-shockwave-flash"},
{".fxp", "application/vnd.adobe.fxp"},
{".pdf", "application/pdf"},
{".ppd", "application/vnd.cups-ppd"},
{".dir", "application/x-director"},
{".xdp", "application/vnd.adobe.xdp+xml"},
{".xfdf", "application/vnd.adobe.xfdf"},
{".aac", "audio/x-aac"},
{".ahead", "application/vnd.ahead.space"},
{".azf", "application/vnd.airzip.filesecure.azf"},
{".azs", "application/vnd.airzip.filesecure.azs"},
{".azw", "application/vnd.amazon.ebook"},
{".ami", "application/vnd.amiga.ami"},
{".apk", "application/vnd.android.package-archive"},
{".cii", "application/vnd.anser-web-certificate-issue-initiation"},
{".fti", "application/vnd.anser-web-funds-transfer-initiation"},
{".atx", "application/vnd.antix.game-component"},
{".dmg", "application/x-apple-diskimage"},
{".mpkg", "application/vnd.apple.installer+xml"},
{".aw", "application/applixware"},
{".les", "application/vnd.hhe.lesson-player"},
{".swi", "application/vnd.aristanetworks.swi"},
{".s", "text/x-asm"},
{".atomcat", "application/atomcat+xml"},
{".atomsvc", "application/atomsvc+xml"},
{".atom", "application/atom+xml"},
{".ac", "application/pkix-attr-cert"},
{".aif", "audio/x-aiff"},
{".avi", "video/x-msvideo"},
{".aep", "application/vnd.audiograph"},
{".dxf", "image/vnd.dxf"},
{".dwf", "model/vnd.dwf"},
{".par", "text/plain-bas"},
{".bcpio", "application/x-bcpio"},
{".bin", "application/octet-stream"},
{".bmp", "image/bmp"},
{".torrent", "application/x-bittorrent"},
{".cod", "application/vnd.rim.cod"},
{".mpm", "application/vnd.blueice.multipass"},
{".bmi", "application/vnd.bmi"},
{".sh", "application/x-sh"},
{".btif", "image/prs.btif"},
{".rep", "application/vnd.businessobjects"},
{".bz", "application/x-bzip"},
{".bz2", "application/x-bzip2"},
{".csh", "application/x-csh"},
{".c", "text/x-c"},
{".cdxml", "application/vnd.chemdraw+xml"},
{".css", "text/css"},
{".cdx", "chemical/x-cdx"},
{".cml", "chemical/x-cml"},
{".csml", "chemical/x-csml"},
{".cdbcmsg", "application/vnd.contact.cmsg"},
{".cla", "application/vnd.claymore"},
{".c4g", "application/vnd.clonk.c4group"},
{".sub", "image/vnd.dvb.subtitle"},
{".cdmia", "application/cdmi-capability"},
{".cdmic", "application/cdmi-container"},
{".cdmid", "application/cdmi-domain"},
{".cdmio", "application/cdmi-object"},
{".cdmiq", "application/cdmi-queue"},
{".c11amc", "application/vnd.cluetrust.cartomobile-config"},
{".c11amz", "application/vnd.cluetrust.cartomobile-config-pkg"},
{".ras", "image/x-cmu-raster"},
{".dae", "model/vnd.collada+xml"},
{".csv", "text/csv"},
{".cpt", "application/mac-compactpro"},
{".wmlc", "application/vnd.wap.wmlc"},
{".cgm", "image/cgm"},
{".ice", "x-conference/x-cooltalk"},
{".cmx", "image/x-cmx"},
{".xar", "application/vnd.xara"},
{".cmc", "application/vnd.cosmocaller"},
{".cpio", "application/x-cpio"},
{".clkx", "application/vnd.crick.clicker"},
{".clkk", "application/vnd.crick.clicker.keyboard"},
{".clkp", "application/vnd.crick.clicker.palette"},
{".clkt", "application/vnd.crick.clicker.template"},
{".clkw", "application/vnd.crick.clicker.wordbank"},
{".wbs", "application/vnd.criticaltools.wbs+xml"},
{".cryptonote", "application/vnd.rig.cryptonote"},
{".cif", "chemical/x-cif"},
{".cmdf", "chemical/x-cmdf"},
{".cu", "application/cu-seeme"},
{".cww", "application/prs.cww"},
{".curl", "text/vnd.curl"},
{".dcurl", "text/vnd.curl.dcurl"},
{".mcurl", "text/vnd.curl.mcurl"},
{".scurl", "text/vnd.curl.scurl"},
{".car", "application/vnd.curl.car"},
{".pcurl", "application/vnd.curl.pcurl"},
{".cmp", "application/vnd.yellowriver-custom-menu"},
{".dssc", "application/dssc+der"},
{".xdssc", "application/dssc+xml"},
{".deb", "application/x-debian-package"},
{".uva", "audio/vnd.dece.audio"},
{".uvi", "image/vnd.dece.graphic"},
{".uvh", "video/vnd.dece.hd"},
{".uvm", "video/vnd.dece.mobile"},
{".uvu", "video/vnd.uvvu.mp4"},
{".uvp", "video/vnd.dece.pd"},
{".uvs", "video/vnd.dece.sd"},
{".uvv", "video/vnd.dece.video"},
{".dvi", "application/x-dvi"},
{".seed", "application/vnd.fdsn.seed"},
{".dtb", "application/x-dtbook+xml"},
{".res", "application/x-dtbresource+xml"},
{".ait", "application/vnd.dvb.ait"},
{".svc", "application/vnd.dvb.service"},
{".eol", "audio/vnd.digital-winds"},
{".djvu", "image/vnd.djvu"},
{".dtd", "application/xml-dtd"},
{".mlp", "application/vnd.dolby.mlp"},
{".wad", "application/x-doom"},
{".dpg", "application/vnd.dpgraph"},
{".dra", "audio/vnd.dra"},
{".dfac", "application/vnd.dreamfactory"},
{".dts", "audio/vnd.dts"},
{".dtshd", "audio/vnd.dts.hd"},
{".dwg", "image/vnd.dwg"},
{".geo", "application/vnd.dynageo"},
{".es", "application/ecmascript"},
{".mag", "application/vnd.ecowin.chart"},
{".mmr", "image/vnd.fujixerox.edmics-mmr"},
{".rlc", "image/vnd.fujixerox.edmics-rlc"},
{".exi", "application/exi"},
{".mgz", "application/vnd.proteus.magazine"},
{".epub", "application/epub+zip"},
{".eml", "message/rfc822"},
{".nml", "application/vnd.enliven"},
{".xpr", "application/vnd.is-xpr"},
{".xif", "image/vnd.xiff"},
{".xfdl", "application/vnd.xfdl"},
{".emma", "application/emma+xml"},
{".ez2", "application/vnd.ezpix-album"},
{".ez3", "application/vnd.ezpix-package"},
{".fst", "image/vnd.fst"},
{".fvt", "video/vnd.fvt"},
{".fbs", "image/vnd.fastbidsheet"},
{".fe_launch", "application/vnd.denovo.fcselayout-link"},
{".f4v", "video/x-f4v"},
{".flv", "video/x-flv"},
{".fpx", "image/vnd.fpx"},
{".npx", "image/vnd.net-fpx"},
{".flx", "text/vnd.fmi.flexstor"},
{".fli", "video/x-fli"},
{".ftc", "application/vnd.fluxtime.clip"},
{".fdf", "application/vnd.fdf"},
{".f", "text/x-fortran"},
{".mif", "application/vnd.mif"},
{".fm", "application/vnd.framemaker"},
{".fh", "image/x-freehand"},
{".fsc", "application/vnd.fsc.weblaunch"},
{".fnc", "application/vnd.frogans.fnc"},
{".ltf", "application/vnd.frogans.ltf"},
{".ddd", "application/vnd.fujixerox.ddd"},
{".xdw", "application/vnd.fujixerox.docuworks"},
{".xbd", "application/vnd.fujixerox.docuworks.binder"},
{".oas", "application/vnd.fujitsu.oasys"},
{".oa2", "application/vnd.fujitsu.oasys2"},
{".oa3", "application/vnd.fujitsu.oasys3"},
{".fg5", "application/vnd.fujitsu.oasysgp"},
{".bh2", "application/vnd.fujitsu.oasysprs"},
{".spl", "application/x-futuresplash"},
{".fzs", "application/vnd.fuzzysheet"},
{".g3", "image/g3fax"},
{".gmx", "application/vnd.gmx"},
{".gtw", "model/vnd.gtw"},
{".txd", "application/vnd.genomatix.tuxedo"},
{".ggb", "application/vnd.geogebra.file"},
{".ggt", "application/vnd.geogebra.tool"},
{".gdl", "model/vnd.gdl"},
{".gex", "application/vnd.geometry-explorer"},
{".gxt", "application/vnd.geonext"},
{".g2w", "application/vnd.geoplan"},
{".g3w", "application/vnd.geospace"},
{".gsf", "application/x-font-ghostscript"},
{".bdf", "application/x-font-bdf"},
{".gtar", "application/x-gtar"},
{".texinfo", "application/x-texinfo"},
{".gnumeric", "application/x-gnumeric"},
{".kml", "application/vnd.google-earth.kml+xml"},
{".kmz", "application/vnd.google-earth.kmz"},
{".gqf", "application/vnd.grafeq"},
{".gif", "image/gif"},
{".gv", "text/vnd.graphviz"},
{".gac", "application/vnd.groove-account"},
{".ghf", "application/vnd.groove-help"},
{".gim", "application/vnd.groove-identity-message"},
{".grv", "application/vnd.groove-injector"},
{".gtm", "application/vnd.groove-tool-message"},
{".tpl", "application/vnd.groove-tool-template"},
{".vcg", "application/vnd.groove-vcard"},
{".h261", "video/h261"},
{".h263", "video/h263"},
{".h264", "video/h264"},
{".hpid", "application/vnd.hp-hpid"},
{".hps", "application/vnd.hp-hps"},
{".hdf", "application/x-hdf"},
{".rip", "audio/vnd.rip"},
{".hbci", "application/vnd.hbci"},
{".jlt", "application/vnd.hp-jlyt"},
{".pcl", "application/vnd.hp-pcl"},
{".hpgl", "application/vnd.hp-hpgl"},
{".hvs", "application/vnd.yamaha.hv-script"},
{".hvd", "application/vnd.yamaha.hv-dic"},
{".hvp", "application/vnd.yamaha.hv-voice"},
{".sfd-hdstx", "application/vnd.hydrostatix.sof-data"},
{".stk", "application/hyperstudio"},
{".hal", "application/vnd.hal+xml"},
{".htm", "text/html; charset=utf-8"},
{".html", "text/html; charset=utf-8"},
{".irm", "application/vnd.ibm.rights-management"},
{".sc", "application/vnd.ibm.secure-container"},
{".ics", "text/calendar"},
{".icc", "application/vnd.iccprofile"},
{".ico", "image/x-icon"},
{".igl", "application/vnd.igloader"},
{".ief", "image/ief"},
{".ivp", "application/vnd.immervision-ivp"},
{".ivu", "application/vnd.immervision-ivu"},
{".rif", "application/reginfo+xml"},
{".3dml", "text/vnd.in3d.3dml"},
{".spot", "text/vnd.in3d.spot"},
{".igs", "model/iges"},
{".i2g", "application/vnd.intergeo"},
{".cdy", "application/vnd.cinderella"},
{".xpw", "application/vnd.intercon.formnet"},
{".fcs", "application/vnd.isac.fcs"},
{".ipfix", "application/ipfix"},
{".cer", "application/pkix-cert"},
{".pki", "application/pkixcmp"},
{".crl", "application/pkix-crl"},
{".pkipath", "application/pkix-pkipath"},
{".igm", "application/vnd.insors.igm"},
{".rcprofile", "application/vnd.ipunplugged.rcprofile"},
{".irp", "application/vnd.irepository.package+xml"},
{".jad", "text/vnd.sun.j2me.app-descriptor"},
{".jar", "application/java-archive"},
{".class", "application/java-vm"},
{".jnlp", "application/x-java-jnlp-file"},
{".ser", "application/java-serialized-object"},
{".java", "text/x-java-source"},
{".js", "application/javascript"},
{".json", "application/json"},
{".joda", "application/vnd.joost.joda-archive"},
{".jpm", "video/jpm"},
{".jpg", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".pjpeg", "image/pjpeg"},
{".jpgv", "video/jpeg"},
{".ktz", "application/vnd.kahootz"},
{".mmd", "application/vnd.chipnuts.karaoke-mmd"},
{".karbon", "application/vnd.kde.karbon"},
{".chrt", "application/vnd.kde.kchart"},
{".kfo", "application/vnd.kde.kformula"},
{".flw", "application/vnd.kde.kivio"},
{".kon", "application/vnd.kde.kontour"},
{".kpr", "application/vnd.kde.kpresenter"},
{".ksp", "application/vnd.kde.kspread"},
{".kwd", "application/vnd.kde.kword"},
{".htke", "application/vnd.kenameaapp"},
{".kia", "application/vnd.kidspiration"},
{".kne", "application/vnd.kinar"},
{".sse", "application/vnd.kodak-descriptor"},
{".lasxml", "application/vnd.las.las+xml"},
{".latex", "application/x-latex"},
{".lbd", "application/vnd.llamagraphics.life-balance.desktop"},
{".lbe", "application/vnd.llamagraphics.life-balance.exchange+xml"},
{".jam", "application/vnd.jam"},
{"0.123", "application/vnd.lotus-1-2-3"},
{".apr", "application/vnd.lotus-approach"},
{".pre", "application/vnd.lotus-freelance"},
{".nsf", "application/vnd.lotus-notes"},
{".org", "application/vnd.lotus-organizer"},
{".scm", "application/vnd.lotus-screencam"},
{".lwp", "application/vnd.lotus-wordpro"},
{".lvp", "audio/vnd.lucent.voice"},
{".m3u", "audio/x-mpegurl"},
{".m4v", "video/x-m4v"},
{".hqx", "application/mac-binhex40"},
{".portpkg", "application/vnd.macports.portpkg"},
{".mgp", "application/vnd.osgeo.mapguide.package"},
{".mrc", "application/marc"},
{".mrcx", "application/marcxml+xml"},
{".mxf", "application/mxf"},
{".nbp", "application/vnd.wolfram.player"},
{".ma", "application/mathematica"},
{".mathml", "application/mathml+xml"},
{".mbox", "application/mbox"},
{".mc1", "application/vnd.medcalcdata"},
{".mscml", "application/mediaservercontrol+xml"},
{".cdkey", "application/vnd.mediastation.cdkey"},
{".mwf", "application/vnd.mfer"},
{".mfm", "application/vnd.mfmp"},
{".msh", "model/mesh"},
{".mads", "application/mads+xml"},
{".mets", "application/mets+xml"},
{".mods", "application/mods+xml"},
{".meta4", "application/metalink4+xml"},
{".mcd", "application/vnd.mcd"},
{".flo", "application/vnd.micrografx.flo"},
{".igx", "application/vnd.micrografx.igx"},
{".es3", "application/vnd.eszigno3+xml"},
{".mdb", "application/x-msaccess"},
{".asf", "video/x-ms-asf"},
{".exe", "application/x-msdownload"},
{".cil", "application/vnd.ms-artgalry"},
{".cab", "application/vnd.ms-cab-compressed"},
{".ims", "application/vnd.ms-ims"},
{".application", "application/x-ms-application"},
{".clp", "application/x-msclip"},
{".mdi", "image/vnd.ms-modi"},
{".eot", "application/vnd.ms-fontobject"},
{".xls", "application/vnd.ms-excel"},
{".xlam", "application/vnd.ms-excel.addin.macroenabled.12"},
{".xlsb", "application/vnd.ms-excel.sheet.binary.macroenabled.12"},
{".xltm", "application/vnd.ms-excel.template.macroenabled.12"},
{".xlsm", "application/vnd.ms-excel.sheet.macroenabled.12"},
{".chm", "application/vnd.ms-htmlhelp"},
{".crd", "application/x-mscardfile"},
{".lrm", "application/vnd.ms-lrm"},
{".mvb", "application/x-msmediaview"},
{".mny", "application/x-msmoney"},
{".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
{".sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide"},
{".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
{".potx", "application/vnd.openxmlformats-officedocument.presentationml.template"},
{".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
{".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"},
{".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
{".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
{".obd", "application/x-msbinder"},
{".thmx", "application/vnd.ms-officetheme"},
{".onetoc", "application/onenote"},
{".pya", "audio/vnd.ms-playready.media.pya"},
{".pyv", "video/vnd.ms-playready.media.pyv"},
{".ppt", "application/vnd.ms-powerpoint"},
{".ppam", "application/vnd.ms-powerpoint.addin.macroenabled.12"},
{".sldm", "application/vnd.ms-powerpoint.slide.macroenabled.12"},
{".pptm", "application/vnd.ms-powerpoint.presentation.macroenabled.12"},
{".ppsm", "application/vnd.ms-powerpoint.slideshow.macroenabled.12"},
{".potm", "application/vnd.ms-powerpoint.template.macroenabled.12"},
{".mpp", "application/vnd.ms-project"},
{".pub", "application/x-mspublisher"},
{".scd", "application/x-msschedule"},
{".xap", "application/x-silverlight-app"},
{".stl", "application/vnd.ms-pki.stl"},
{".cat", "application/vnd.ms-pki.seccat"},
{".vsd", "application/vnd.visio"},
{".vsdx", "application/vnd.visio2013"},
{".wm", "video/x-ms-wm"},
{".wma", "audio/x-ms-wma"},
{".wax", "audio/x-ms-wax"},
{".wmx", "video/x-ms-wmx"},
{".wmd", "application/x-ms-wmd"},
{".wpl", "application/vnd.ms-wpl"},
{".wmz", "application/x-ms-wmz"},
{".wmv", "video/x-ms-wmv"},
{".wvx", "video/x-ms-wvx"},
{".wmf", "application/x-msmetafile"},
{".trm", "application/x-msterminal"},
{".doc", "application/msword"},
{".docm", "application/vnd.ms-word.document.macroenabled.12"},
{".dotm", "application/vnd.ms-word.template.macroenabled.12"},
{".wri", "application/x-mswrite"},
{".wps", "application/vnd.ms-works"},
{".xbap", "application/x-ms-xbap"},
{".xps", "application/vnd.ms-xpsdocument"},
{".mid", "audio/midi"},
{".mpy", "application/vnd.ibm.minipay"},
{".afp", "application/vnd.ibm.modcap"},
{".rms", "application/vnd.jcp.javame.midlet-rms"},
{".tmo", "application/vnd.tmobile-livetv"},
{".prc", "application/x-mobipocket-ebook"},
{".mbk", "application/vnd.mobius.mbk"},
{".dis", "application/vnd.mobius.dis"},
{".plc", "application/vnd.mobius.plc"},
{".mqy", "application/vnd.mobius.mqy"},
{".msl", "application/vnd.mobius.msl"},
{".txf", "application/vnd.mobius.txf"},
{".daf", "application/vnd.mobius.daf"},
{".fly", "text/vnd.fly"},
{".mpc", "application/vnd.mophun.certificate"},
{".mpn", "application/vnd.mophun.application"},
{".mj2", "video/mj2"},
{".mpga", "audio/mpeg"},
{".mxu", "video/vnd.mpegurl"},
{".mpeg", "video/mpeg"},
{".m21", "application/mp21"},
{".mp4a", "audio/mp4"},
{".mp4", "video/mp4"},
{".mp4", "application/mp4"},
{".m3u8", "application/vnd.apple.mpegurl"},
{".mus", "application/vnd.musician"},
{".msty", "application/vnd.muvee.style"},
{".mxml", "application/xv+xml"},
{".ngdat", "application/vnd.nokia.n-gage.data"},
{".n-gage", "application/vnd.nokia.n-gage.symbian.install"},
{".ncx", "application/x-dtbncx+xml"},
{".nc", "application/x-netcdf"},
{".nlu", "application/vnd.neurolanguage.nlu"},
{".dna", "application/vnd.dna"},
{".nnd", "application/vnd.noblenet-directory"},
{".nns", "application/vnd.noblenet-sealer"},
{".nnw", "application/vnd.noblenet-web"},
{".rpst", "application/vnd.nokia.radio-preset"},
{".rpss", "application/vnd.nokia.radio-presets"},
{".n3", "text/n3"},
{".edm", "application/vnd.novadigm.edm"},
{".edx", "application/vnd.novadigm.edx"},
{".ext", "application/vnd.novadigm.ext"},
{".gph", "application/vnd.flographit"},
{".ecelp4800", "audio/vnd.nuera.ecelp4800"},
{".ecelp7470", "audio/vnd.nuera.ecelp7470"},
{".ecelp9600", "audio/vnd.nuera.ecelp9600"},
{".oda", "application/oda"},
{".ogx", "application/ogg"},
{".oga", "audio/ogg"},
{".ogv", "video/ogg"},
{".dd2", "application/vnd.oma.dd2+xml"},
{".oth", "application/vnd.oasis.opendocument.text-web"},
{".opf", "application/oebps-package+xml"},
{".qbo", "application/vnd.intu.qbo"},
{".oxt", "application/vnd.openofficeorg.extension"},
{".osf", "application/vnd.yamaha.openscoreformat"},
{".weba", "audio/webm"},
{".webm", "video/webm"},
{".odc", "application/vnd.oasis.opendocument.chart"},
{".otc", "application/vnd.oasis.opendocument.chart-template"},
{".odb", "application/vnd.oasis.opendocument.database"},
{".odf", "application/vnd.oasis.opendocument.formula"},
{".odft", "application/vnd.oasis.opendocument.formula-template"},
{".odg", "application/vnd.oasis.opendocument.graphics"},
{".otg", "application/vnd.oasis.opendocument.graphics-template"},
{".odi", "application/vnd.oasis.opendocument.image"},
{".oti", "application/vnd.oasis.opendocument.image-template"},
{".odp", "application/vnd.oasis.opendocument.presentation"},
{".otp", "application/vnd.oasis.opendocument.presentation-template"},
{".ods", "application/vnd.oasis.opendocument.spreadsheet"},
{".ots", "application/vnd.oasis.opendocument.spreadsheet-template"},
{".odt", "application/vnd.oasis.opendocument.text"},
{".odm", "application/vnd.oasis.opendocument.text-master"},
{".ott", "application/vnd.oasis.opendocument.text-template"},
{".ktx", "image/ktx"},
{".sxc", "application/vnd.sun.xml.calc"},
{".stc", "application/vnd.sun.xml.calc.template"},
{".sxd", "application/vnd.sun.xml.draw"},
{".std", "application/vnd.sun.xml.draw.template"},
{".sxi", "application/vnd.sun.xml.impress"},
{".sti", "application/vnd.sun.xml.impress.template"},
{".sxm", "application/vnd.sun.xml.math"},
{".sxw", "application/vnd.sun.xml.writer"},
{".sxg", "application/vnd.sun.xml.writer.global"},
{".stw", "application/vnd.sun.xml.writer.template"},
{".otf", "application/x-font-otf"},
{".osfpvg", "application/vnd.yamaha.openscoreformat.osfpvg+xml"},
{".dp", "application/vnd.osgi.dp"},
{".pdb", "application/vnd.palm"},
{".p", "text/x-pascal"},
{".paw", "application/vnd.pawaafile"},
{".pclxl", "application/vnd.hp-pclxl"},
{".efif", "application/vnd.picsel"},
{".pcx", "image/x-pcx"},
{".psd", "image/vnd.adobe.photoshop"},
{".prf", "application/pics-rules"},
{".pic", "image/x-pict"},
{".chat", "application/x-chat"},
{".p10", "application/pkcs10"},
{".p12", "application/x-pkcs12"},
{".p7m", "application/pkcs7-mime"},
{".p7s", "application/pkcs7-signature"},
{".p7r", "application/x-pkcs7-certreqresp"},
{".p7b", "application/x-pkcs7-certificates"},
{".p8", "application/pkcs8"},
{".plf", "application/vnd.pocketlearn"},
{".pnm", "image/x-portable-anymap"},
{".pbm", "image/x-portable-bitmap"},
{".pcf", "application/x-font-pcf"},
{".pfr", "application/font-tdpfr"},
{".pgn", "application/x-chess-pgn"},
{".pgm", "image/x-portable-graymap"},
{".png", "image/png"},
{".png", "image/x-citrix-png"},
{".png", "image/x-png"},
{".ppm", "image/x-portable-pixmap"},
{".pskcxml", "application/pskc+xml"},
{".pml", "application/vnd.ctc-posml"},
{".ai", "application/postscript"},
{".pfa", "application/x-font-type1"},
{".pbd", "application/vnd.powerbuilder6"},
{".pgp", "application/pgp-encrypted"},
{".pgp", "application/pgp-signature"},
{".box", "application/vnd.previewsystems.box"},
{".ptid", "application/vnd.pvi.ptid1"},
{".pls", "application/pls+xml"},
{".str", "application/vnd.pg.format"},
{".ei6", "application/vnd.pg.osasli"},
{".dsc", "text/prs.lines.tag"},
{".psf", "application/x-font-linux-psf"},
{".qps", "application/vnd.publishare-delta-tree"},
{".wg", "application/vnd.pmi.widget"},
{".qxd", "application/vnd.quark.quarkxpress"},
{".esf", "application/vnd.epson.esf"},
{".msf", "application/vnd.epson.msf"},
{".ssf", "application/vnd.epson.ssf"},
{".qam", "application/vnd.epson.quickanime"},
{".qfx", "application/vnd.intu.qfx"},
{".qt", "video/quicktime"},
{".rar", "application/x-rar-compressed"},
{".ram", "audio/x-pn-realaudio"},
{".rmp", "audio/x-pn-realaudio-plugin"},
{".rsd", "application/rsd+xml"},
{".rm", "application/vnd.rn-realmedia"},
{".bed", "application/vnd.realvnc.bed"},
{".mxl", "application/vnd.recordare.musicxml"},
{".musicxml", "application/vnd.recordare.musicxml+xml"},
{".rnc", "application/relax-ng-compact-syntax"},
{".rdz", "application/vnd.data-vision.rdz"},
{".rdf", "application/rdf+xml"},
{".rp9", "application/vnd.cloanto.rp9"},
{".jisp", "application/vnd.jisp"},
{".rtf", "application/rtf"},
{".rtx", "text/richtext"},
{".link66", "application/vnd.route66.link66+xml"},
{".rss", "application/rss+xml"},
{".shf", "application/shf+xml"},
{".st", "application/vnd.sailingtracker.track"},
{".svg", "image/svg+xml"},
{".sus", "application/vnd.sus-calendar"},
{".sru", "application/sru+xml"},
{".setpay", "application/set-payment-initiation"},
{".setreg", "application/set-registration-initiation"},
{".sema", "application/vnd.sema"},
{".semd", "application/vnd.semd"},
{".semf", "application/vnd.semf"},
{".see", "application/vnd.seemail"},
{".snf", "application/x-font-snf"},
{".spq", "application/scvp-vp-request"},
{".spp", "application/scvp-vp-response"},
{".scq", "application/scvp-cv-request"},
{".scs", "application/scvp-cv-response"},
{".sdp", "application/sdp"},
{".etx", "text/x-setext"},
{".movie", "video/x-sgi-movie"},
{".ifm", "application/vnd.shana.informed.formdata"},
{".itp", "application/vnd.shana.informed.formtemplate"},
{".iif", "application/vnd.shana.informed.interchange"},
{".ipk", "application/vnd.shana.informed.package"},
{".tfi", "application/thraud+xml"},
{".shar", "application/x-shar"},
{".rgb", "image/x-rgb"},
{".slt", "application/vnd.epson.salt"},
{".aso", "application/vnd.accpac.simply.aso"},
{".imp", "application/vnd.accpac.simply.imp"},
{".twd", "application/vnd.simtech-mindmapper"},
{".csp", "application/vnd.commonspace"},
{".saf", "application/vnd.yamaha.smaf-audio"},
{".mmf", "application/vnd.smaf"},
{".spf", "application/vnd.yamaha.smaf-phrase"},
{".teacher", "application/vnd.smart.teacher"},
{".svd", "application/vnd.svd"},
{".rq", "application/sparql-query"},
{".srx", "application/sparql-results+xml"},
{".gram", "application/srgs"},
{".grxml", "application/srgs+xml"},
{".ssml", "application/ssml+xml"},
{".skp", "application/vnd.koan"},
{".sgml", "text/sgml"},
{".sdc", "application/vnd.stardivision.calc"},
{".sda", "application/vnd.stardivision.draw"},
{".sdd", "application/vnd.stardivision.impress"},
{".smf", "application/vnd.stardivision.math"},
{".sdw", "application/vnd.stardivision.writer"},
{".sgl", "application/vnd.stardivision.writer-global"},
{".sm", "application/vnd.stepmania.stepchart"},
{".sit", "application/x-stuffit"},
{".sitx", "application/x-stuffitx"},
{".sdkm", "application/vnd.solent.sdkm+xml"},
{".xo", "application/vnd.olpc-sugar"},
{".au", "audio/basic"},
{".wqd", "application/vnd.wqd"},
{".sis", "application/vnd.symbian.install"},
{".smi", "application/smil+xml"},
{".xsm", "application/vnd.syncml+xml"},
{".bdm", "application/vnd.syncml.dm+wbxml"},
{".xdm", "application/vnd.syncml.dm+xml"},
{".sv4cpio", "application/x-sv4cpio"},
{".sv4crc", "application/x-sv4crc"},
{".sbml", "application/sbml+xml"},
{".tsv", "text/tab-separated-values"},
{".tiff", "image/tiff"},
{".tao", "application/vnd.tao.intent-module-archive"},
{".tar", "application/x-tar"},
{".tcl", "application/x-tcl"},
{".tex", "application/x-tex"},
{".tfm", "application/x-tex-tfm"},
{".tei", "application/tei+xml"},
{".txt", "text/plain; charset=utf-8"},
{".md", "text/markdown; charset=utf-8"},
{".dxp", "application/vnd.spotfire.dxp"},
{".sfs", "application/vnd.spotfire.sfs"},
{".tsd", "application/timestamped-data"},
{".tpt", "application/vnd.trid.tpt"},
{".mxs", "application/vnd.triscape.mxs"},
{".t", "text/troff"},
{".tra", "application/vnd.trueapp"},
{".ttf", "application/x-font-ttf"},
{".ttl", "text/turtle"},
{".umj", "application/vnd.umajin"},
{".uoml", "application/vnd.uoml+xml"},
{".unityweb", "application/vnd.unity"},
{".ufd", "application/vnd.ufdl"},
{".uri", "text/uri-list"},
{".utz", "application/vnd.uiq.theme"},
{".ustar", "application/x-ustar"},
{".uu", "text/x-uuencode"},
{".vcs", "text/x-vcalendar"},
{".vcf", "text/x-vcard"},
{".vcd", "application/x-cdlink"},
{".vsf", "application/vnd.vsf"},
{".wrl", "model/vrml"},
{".vcx", "application/vnd.vcx"},
{".mts", "model/vnd.mts"},
{".vtu", "model/vnd.vtu"},
{".vis", "application/vnd.visionary"},
{".viv", "video/vnd.vivo"},
{".ccxml", "application/ccxml+xml"},
{".vxml", "application/voicexml+xml"},
{".src", "application/x-wais-source"},
{".wbxml", "application/vnd.wap.wbxml"},
{".wbmp", "image/vnd.wap.wbmp"},
{".wav", "audio/x-wav"},
{".davmount", "application/davmount+xml"},
{".woff", "application/x-font-woff"},
{".wspolicy", "application/wspolicy+xml"},
{".webp", "image/webp"},
{".wtb", "application/vnd.webturbo"},
{".wgt", "application/widget"},
{".hlp", "application/winhlp"},
{".wml", "text/vnd.wap.wml"},
{".wmls", "text/vnd.wap.wmlscript"},
{".wmlsc", "application/vnd.wap.wmlscriptc"},
{".wpd", "application/vnd.wordperfect"},
{".stf", "application/vnd.wt.stf"},
{".wsdl", "application/wsdl+xml"},
{".xbm", "image/x-xbitmap"},
{".xpm", "image/x-xpixmap"},
{".xwd", "image/x-xwindowdump"},
{".der", "application/x-x509-ca-cert"},
{".fig", "application/x-xfig"},
{".xhtml", "application/xhtml+xml"},
{".xml", "application/xml"},
{".xdf", "application/xcap-diff+xml"},
{".xenc", "application/xenc+xml"},
{".xer", "application/patch-ops-error+xml"},
{".rl", "application/resource-lists+xml"},
{".rs", "application/rls-services+xml"},
{".rld", "application/resource-lists-diff+xml"},
{".xslt", "application/xslt+xml"},
{".xop", "application/xop+xml"},
{".xpi", "application/x-xpinstall"},
{".xspf", "application/xspf+xml"},
{".xul", "application/vnd.mozilla.xul+xml"},
{".xyz", "chemical/x-xyz"},
{".yaml", "text/yaml"},
{".yang", "application/yang"},
{".yin", "application/yin+xml"},
{".zir", "application/vnd.zul"},
{".zip", "application/zip"},
{".zmm", "application/vnd.handheld-entertainment+xml"},
{".zaz", "application/vnd.zzazz.deck+xml"},
};
// Get HTTP MIME type from filename
char *GetMimeTypeFromFileName(char *filename)
{
UINT i;
UINT num = sizeof(http_mime_types) / sizeof(HTTP_MIME_TYPE);
if (filename == NULL)
{
return NULL;
}
for (i = 0;i < num;i++)
{
HTTP_MIME_TYPE *a = &http_mime_types[i];
if (EndWith(filename, a->Extension))
{
return a->MimeType;
}
}
return NULL;
}
// Download and save intermediate certificates if necessary // Download and save intermediate certificates if necessary
bool DownloadAndSaveIntermediateCertificatesIfNecessary(X *x) bool DownloadAndSaveIntermediateCertificatesIfNecessary(X *x)
{ {
@ -1183,6 +1903,11 @@ bool ServerAccept(CONNECTION *c)
error_detail_2 = NULL; error_detail_2 = NULL;
if (ServerDownloadSignature(c, &error_detail_2) == false) if (ServerDownloadSignature(c, &error_detail_2) == false)
{ {
if (c->Type == CONNECTION_TYPE_ADMIN_RPC)
{
c->Err = ERR_NO_ERROR;
}
if (error_detail_2 == NULL) if (error_detail_2 == NULL)
{ {
error_detail = "ServerDownloadSignature"; error_detail = "ServerDownloadSignature";
@ -5045,11 +5770,11 @@ PACK *PackWelcome(SESSION *s)
} }
#define PACK_ADD_POLICY_BOOL(name, value) \ #define PACK_ADD_POLICY_BOOL(name, value) \
PackAddInt(p, "policy:" name, y->value == false ? 0 : 1) PackAddBool(p, "policy:" name, y->value == false ? 0 : 1)
#define PACK_ADD_POLICY_UINT(name, value) \ #define PACK_ADD_POLICY_UINT(name, value) \
PackAddInt(p, "policy:" name, y->value) PackAddInt(p, "policy:" name, y->value)
#define PACK_GET_POLICY_BOOL(name, value) \ #define PACK_GET_POLICY_BOOL(name, value) \
y->value = (PackGetInt(p, "policy:" name) == 0 ? false : true) y->value = (PackGetBool(p, "policy:" name))
#define PACK_GET_POLICY_UINT(name, value) \ #define PACK_GET_POLICY_UINT(name, value) \
y->value = PackGetInt(p, "policy:" name) y->value = PackGetInt(p, "policy:" name)
@ -5560,6 +6285,10 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
if (h == NULL) if (h == NULL)
{ {
c->Err = ERR_CLIENT_IS_NOT_VPN; c->Err = ERR_CLIENT_IS_NOT_VPN;
if (c->IsJsonRpc)
{
c->Err = ERR_DISCONNECTED;
}
return false; return false;
} }
@ -5568,6 +6297,43 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
{ {
// Receive the data since it's POST // Receive the data since it's POST
data_size = GetContentLength(h); data_size = GetContentLength(h);
if (server->DisableJsonRpcWebApi == false)
{
if (StrCmpi(h->Target, "/api") == 0 || StrCmpi(h->Target, "/api/") == 0)
{
c->IsJsonRpc = true;
c->Type = CONNECTION_TYPE_ADMIN_RPC;
JsonRpcProcPost(c, s, h, data_size);
FreeHttpHeader(h);
if (c->JsonRpcAuthed)
{
num = 0;
}
continue;
}
else if (StartWith(h->Target, "/admin"))
{
c->IsJsonRpc = true;
c->Type = CONNECTION_TYPE_ADMIN_RPC;
AdminWebProcPost(c, s, h, data_size, h->Target);
FreeHttpHeader(h);
if (c->JsonRpcAuthed)
{
num = 0;
}
continue;
}
}
if ((data_size > MAX_WATERMARK_SIZE || data_size < SizeOfWaterMark()) && (data_size != StrLen(HTTP_VPN_TARGET_POSTDATA))) if ((data_size > MAX_WATERMARK_SIZE || data_size < SizeOfWaterMark()) && (data_size != StrLen(HTTP_VPN_TARGET_POSTDATA)))
{ {
// Data is too large // Data is too large
@ -5616,6 +6382,25 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
} }
} }
} }
else if (StrCmpi(h->Method, "OPTIONS") == 0)
{
if (server->DisableJsonRpcWebApi == false)
{
if (StrCmpi(h->Target, "/api") == 0 || StrCmpi(h->Target, "/api/") == 0 || StartWith(h->Target, "/admin"))
{
c->IsJsonRpc = true;
c->Type = CONNECTION_TYPE_ADMIN_RPC;
JsonRpcProcOptions(c, s, h, h->Target);
FreeHttpHeader(h);
num = 0;
continue;
}
}
}
else if (StrCmpi(h->Method, "SSTP_DUPLEX_POST") == 0 && (server->DisableSSTPServer == false || s->IsReverseAcceptedSocket else if (StrCmpi(h->Method, "SSTP_DUPLEX_POST") == 0 && (server->DisableSSTPServer == false || s->IsReverseAcceptedSocket
) && ) &&
GetServerCapsBool(server, "b_support_sstp") && GetNoSstp() == false) GetServerCapsBool(server, "b_support_sstp") && GetNoSstp() == false)
@ -5733,6 +6518,45 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
} }
} }
if (b == false)
{
if (server->DisableJsonRpcWebApi == false)
{
if (StartWith(h->Target, "/api?") || StartWith(h->Target, "/api/") || StrCmpi(h->Target, "/api") == 0)
{
c->IsJsonRpc = true;
c->Type = CONNECTION_TYPE_ADMIN_RPC;
JsonRpcProcGet(c, s, h, h->Target);
if (c->JsonRpcAuthed)
{
num = 0;
}
FreeHttpHeader(h);
continue;
}
else if (StartWith(h->Target, "/admin"))
{
c->IsJsonRpc = true;
c->Type = CONNECTION_TYPE_ADMIN_RPC;
AdminWebProcGet(c, s, h, h->Target);
if (c->JsonRpcAuthed)
{
num = 0;
}
FreeHttpHeader(h);
continue;
}
}
}
if (b == false) if (b == false)
{ {
// Not Found // Not Found

View File

@ -8,6 +8,13 @@
#ifndef PROTOCOL_H #ifndef PROTOCOL_H
#define PROTOCOL_H #define PROTOCOL_H
// MIME types
struct HTTP_MIME_TYPE
{
char *Extension;
char *MimeType;
};
// The parameters that will be passed to the certificate confirmation thread // The parameters that will be passed to the certificate confirmation thread
struct CHECK_CERT_THREAD_PROC struct CHECK_CERT_THREAD_PROC
{ {
@ -190,6 +197,6 @@ X *FindCertIssuerFromCertList(LIST *o, X *x);
bool TryGetRootCertChain(LIST *o, X *x, bool auto_save, X **found_root_x); bool TryGetRootCertChain(LIST *o, X *x, bool auto_save, X **found_root_x);
bool TryGetParentCertFromCertList(LIST *o, X *x, LIST *found_chain); bool TryGetParentCertFromCertList(LIST *o, X *x, LIST *found_chain);
bool DownloadAndSaveIntermediateCertificatesIfNecessary(X *x); bool DownloadAndSaveIntermediateCertificatesIfNecessary(X *x);
char *GetMimeTypeFromFileName(char *filename);
#endif // PROTOCOL_H #endif // PROTOCOL_H

View File

@ -15,6 +15,10 @@ void EndRpc(RPC *rpc)
// Release the RPC // Release the RPC
void RpcFree(RPC *rpc) void RpcFree(RPC *rpc)
{
RpcFreeEx(rpc, false);
}
void RpcFreeEx(RPC *rpc, bool no_disconnect)
{ {
// Validate arguments // Validate arguments
if (rpc == NULL) if (rpc == NULL)
@ -22,7 +26,11 @@ void RpcFree(RPC *rpc)
return; return;
} }
Disconnect(rpc->Sock); if (no_disconnect == false)
{
Disconnect(rpc->Sock);
}
ReleaseSock(rpc->Sock); ReleaseSock(rpc->Sock);
DeleteLock(rpc->Lock); DeleteLock(rpc->Lock);

View File

@ -42,6 +42,7 @@ bool RpcIsOk(PACK *p);
UINT RpcGetError(PACK *p); UINT RpcGetError(PACK *p);
void EndRpc(RPC *rpc); void EndRpc(RPC *rpc);
void RpcFree(RPC *rpc); void RpcFree(RPC *rpc);
void RpcFreeEx(RPC *rpc, bool no_disconnect);
#endif // REMOTE_H #endif // REMOTE_H

View File

@ -974,52 +974,70 @@ LIST *EnumLogFile(char *hubname)
// Enumerate in the packet_log // Enumerate in the packet_log
Format(tmp, sizeof(tmp), "%s/packet_log", exe_dir); Format(tmp, sizeof(tmp), "%s/packet_log", exe_dir);
dir = EnumDir(tmp);
if (dir != NULL) if (hubname == NULL)
{ {
UINT i; dir = EnumDir(tmp);
for (i = 0;i < dir->NumFiles;i++) if (dir != NULL)
{ {
DIRENT *e = dir->File[i]; UINT i;
for (i = 0;i < dir->NumFiles;i++)
if (e->Folder)
{ {
char dir_name[MAX_PATH]; DIRENT *e = dir->File[i];
if (hubname == NULL || StrCmpi(hubname, e->FileName) == 0) if (e->Folder)
{ {
char dir_name[MAX_PATH];
Format(dir_name, sizeof(dir_name), "packet_log/%s", e->FileName); Format(dir_name, sizeof(dir_name), "packet_log/%s", e->FileName);
EnumLogFileDir(o, dir_name); EnumLogFileDir(o, dir_name);
} }
} }
}
FreeDir(dir); FreeDir(dir);
}
}
else
{
char dir_name[MAX_PATH];
Format(dir_name, sizeof(dir_name), "packet_log/%s", hubname);
EnumLogFileDir(o, dir_name);
} }
// Enumerate in the security_log // Enumerate in the security_log
Format(tmp, sizeof(tmp), "%s/security_log", exe_dir); Format(tmp, sizeof(tmp), "%s/security_log", exe_dir);
dir = EnumDir(tmp);
if (dir != NULL) if (hubname == NULL)
{ {
UINT i; dir = EnumDir(tmp);
for (i = 0;i < dir->NumFiles;i++) if (dir != NULL)
{ {
DIRENT *e = dir->File[i]; UINT i;
for (i = 0;i < dir->NumFiles;i++)
if (e->Folder)
{ {
char dir_name[MAX_PATH]; DIRENT *e = dir->File[i];
if (hubname == NULL || StrCmpi(hubname, e->FileName) == 0) if (e->Folder)
{ {
char dir_name[MAX_PATH];
Format(dir_name, sizeof(dir_name), "security_log/%s", e->FileName); Format(dir_name, sizeof(dir_name), "security_log/%s", e->FileName);
EnumLogFileDir(o, dir_name); EnumLogFileDir(o, dir_name);
} }
} }
}
FreeDir(dir); FreeDir(dir);
}
}
else
{
char dir_name[MAX_PATH];
Format(dir_name, sizeof(dir_name), "security_log/%s", hubname);
EnumLogFileDir(o, dir_name);
} }
return o; return o;
@ -1731,14 +1749,37 @@ void OutRpcCapsList(PACK *p, CAPSLIST *t)
return; return;
} }
PackSetCurrentJsonGroupName(p, "CapsList");
for (i = 0;i < LIST_NUM(t->CapsList);i++) for (i = 0;i < LIST_NUM(t->CapsList);i++)
{ {
char tmp[MAX_SIZE]; char tmp[MAX_SIZE];
char ct_key[MAX_PATH];
wchar_t ct_description[MAX_PATH];
wchar_t *w;
CAPS *c = LIST_DATA(t->CapsList, i); CAPS *c = LIST_DATA(t->CapsList, i);
Format(tmp, sizeof(tmp), "caps_%s", c->Name); Format(tmp, sizeof(tmp), "caps_%s", c->Name);
Format(ct_key, sizeof(ct_key), "CT_%s", c->Name);
Zero(ct_description, sizeof(ct_description));
w = _UU(ct_key);
if (UniIsEmptyStr(w) == false)
{
UniStrCpy(ct_description, sizeof(ct_description), w);
}
else
{
StrToUni(ct_description, sizeof(ct_description), c->Name);
}
PackAddInt(p, tmp, c->Value); PackAddInt(p, tmp, c->Value);
PackAddStrEx(p, "CapsName", c->Name, i, LIST_NUM(t->CapsList));
PackAddIntEx(p, "CapsValue", c->Value, i, LIST_NUM(t->CapsList));
PackAddUniStrEx(p, "CapsDescrption", ct_description, i, LIST_NUM(t->CapsList));
} }
PackSetCurrentJsonGroupName(p, NULL);
} }
void FreeRpcCapsList(CAPSLIST *t) void FreeRpcCapsList(CAPSLIST *t)
{ {
@ -5982,7 +6023,11 @@ void SiLoadServerCfg(SERVER *s, FOLDER *f)
c->SslAcceptSettings.Tls_Disable1_2 = CfgGetBool(f, "Tls_Disable1_2"); c->SslAcceptSettings.Tls_Disable1_2 = CfgGetBool(f, "Tls_Disable1_2");
s->StrictSyslogDatetimeFormat = CfgGetBool(f, "StrictSyslogDatetimeFormat"); s->StrictSyslogDatetimeFormat = CfgGetBool(f, "StrictSyslogDatetimeFormat");
// Bits of Diffie-Hellman parameters
// Disable JSON-RPC Web API
s->DisableJsonRpcWebApi = CfgGetBool(f, "DisableJsonRpcWebApi");
// Bits of Diffie-Hellman parameters
c->DhParamBits = CfgGetInt(f, "DhParamBits"); c->DhParamBits = CfgGetInt(f, "DhParamBits");
if (c->DhParamBits == 0) if (c->DhParamBits == 0)
{ {
@ -6314,6 +6359,9 @@ void SiWriteServerCfg(FOLDER *f, SERVER *s)
CfgAddBool(f, "DisableSessionReconnect", GetGlobalServerFlag(GSF_DISABLE_SESSION_RECONNECT)); CfgAddBool(f, "DisableSessionReconnect", GetGlobalServerFlag(GSF_DISABLE_SESSION_RECONNECT));
CfgAddBool(f, "StrictSyslogDatetimeFormat", s->StrictSyslogDatetimeFormat); CfgAddBool(f, "StrictSyslogDatetimeFormat", s->StrictSyslogDatetimeFormat);
// Disable JSON-RPC Web API
CfgAddBool(f, "DisableJsonRpcWebApi", s->DisableJsonRpcWebApi);
} }
Unlock(c->lock); Unlock(c->lock);
} }
@ -7031,7 +7079,7 @@ FARM_MEMBER *SiGetNextFarmMember(SERVER *s, CONNECTION *c, HUB *h)
PackAddIntEx(p, "NumTcpConnections", f->NumTcpConnections, i, num); PackAddIntEx(p, "NumTcpConnections", f->NumTcpConnections, i, num);
PackAddIntEx(p, "NumHubs", LIST_NUM(f->HubList), i, num); PackAddIntEx(p, "NumHubs", LIST_NUM(f->HubList), i, num);
PackAddBoolEx(p, "Me", f->Me, i, num); PackAddBoolEx(p, "Me", f->Me, i, num);
PackAddInt64Ex(p, "ConnectedTime", f->ConnectedTime, i, num); PackAddTime64Ex(p, "ConnectedTime", f->ConnectedTime, i, num);
PackAddInt64Ex(p, "SystemId", f->SystemId, i, num); PackAddInt64Ex(p, "SystemId", f->SystemId, i, num);
PackAddBoolEx(p, "DoNotSelect", do_not_select, i, num); PackAddBoolEx(p, "DoNotSelect", do_not_select, i, num);
} }
@ -7060,7 +7108,7 @@ FARM_MEMBER *SiGetNextFarmMember(SERVER *s, CONNECTION *c, HUB *h)
PackAddStr(p, "CipherName", c->CipherName); PackAddStr(p, "CipherName", c->CipherName);
PackAddStr(p, "ClientStr", c->ClientStr); PackAddStr(p, "ClientStr", c->ClientStr);
PackAddInt(p, "ClientVer", c->ClientVer); PackAddInt(p, "ClientVer", c->ClientVer);
PackAddInt64(p, "ConnectedTime", Tick64ToTime64(c->ConnectedTick)); PackAddTime64(p, "ConnectedTime", Tick64ToTime64(c->ConnectedTick));
PackAddStr(p, "HubName", h->Name); PackAddStr(p, "HubName", h->Name);
PackAddBool(p, "StaticHub", h->Type == HUB_TYPE_FARM_STATIC); PackAddBool(p, "StaticHub", h->Type == HUB_TYPE_FARM_STATIC);
@ -7200,8 +7248,8 @@ void SiCalledEnumHub(SERVER *s, PACK *p, PACK *req)
PackAddIntEx(p, "NumIpTables", LIST_NUM(h->IpTable), i, num); PackAddIntEx(p, "NumIpTables", LIST_NUM(h->IpTable), i, num);
PackAddInt64Ex(p, "LastCommTime", h->LastCommTime, i, num); PackAddTime64Ex(p, "LastCommTime", h->LastCommTime, i, num);
PackAddInt64Ex(p, "CreatedTime", h->CreatedTime, i, num); PackAddTime64Ex(p, "CreatedTime", h->CreatedTime, i, num);
} }
Unlock(h->lock); Unlock(h->lock);
} }

View File

@ -267,6 +267,7 @@ struct SERVER
IP ListenIP; // Listen IP IP ListenIP; // Listen IP
bool StrictSyslogDatetimeFormat; // Make syslog datetime format strict RFC3164 bool StrictSyslogDatetimeFormat; // Make syslog datetime format strict RFC3164
bool DisableJsonRpcWebApi; // Disable JSON-RPC Web API
}; };
@ -290,6 +291,7 @@ struct RPC_SESSION_STATUS
RPC_CLIENT_GET_CONNECTION_STATUS Status; // Status RPC_CLIENT_GET_CONNECTION_STATUS Status; // Status
UINT ClientIp; // Client IP address UINT ClientIp; // Client IP address
UCHAR ClientIp6[16]; // Client IPv6 address UCHAR ClientIp6[16]; // Client IPv6 address
IP ClientIpAddress; // Client IP address (IPv4/IPv6)
char ClientHostName[MAX_HOST_NAME_LEN + 1]; // Client host name char ClientHostName[MAX_HOST_NAME_LEN + 1]; // Client host name
NODE_INFO NodeInfo; // Node information NODE_INFO NodeInfo; // Node information
}; };

View File

@ -108,9 +108,9 @@ void SessionMain(SESSION *s)
s->NumConnectionsEstablished++; s->NumConnectionsEstablished++;
s->CurrentConnectionEstablishTime = Tick64(); s->CurrentConnectionEstablishTime = Tick64();
if (s->FirstConnectionEstablishedTime == 0) if (s->FirstConnectionEstablisiedTime == 0) /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
{ {
s->FirstConnectionEstablishedTime = Tick64(); s->FirstConnectionEstablisiedTime = Tick64(); /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
} }
if (s->ServerMode == false && s->Cedar->Client != NULL) if (s->ServerMode == false && s->Cedar->Client != NULL)
@ -1158,7 +1158,10 @@ void StopSessionEx(SESSION *s, bool no_wait)
// Server and client mode // Server and client mode
if (s->Connection) if (s->Connection)
{ {
StopConnection(s->Connection, no_wait); CONNECTION *c = s->Connection;
AddRef(c->ref);
StopConnection(c, no_wait);
ReleaseConnection(c);
} }
// Wait until the stop // Wait until the stop

View File

@ -157,7 +157,8 @@ struct SESSION
UINT NumDisconnected; // Number of socket disconnection UINT NumDisconnected; // Number of socket disconnection
bool NoReconnectToSession; // Disable to reconnect to the session bool NoReconnectToSession; // Disable to reconnect to the session
char UnderlayProtocol[64]; // Physical communication protocol char UnderlayProtocol[64]; // Physical communication protocol
UINT64 FirstConnectionEstablishedTime; // Connection completion time of the first connection /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
UINT64 FirstConnectionEstablisiedTime; // Connection completion time of the first connection
UINT64 CurrentConnectionEstablishTime; // Completion time of this connection UINT64 CurrentConnectionEstablishTime; // Completion time of this connection
UINT NumConnectionsEstablished; // Number of connections established so far UINT NumConnectionsEstablished; // Number of connections established so far
UINT AdjustMss; // MSS adjustment value UINT AdjustMss; // MSS adjustment value

View File

@ -1127,6 +1127,12 @@ void BuildHamcore(char *dst_filename, char *src_dir, bool unix_only)
} }
} }
if (InStr(rpath, "\\node_modules\\"))
{
// Exclude node_modules in the hamcore\webroot
ok = false;
}
if (ok) if (ok)
{ {
b = ReadDump(s); b = ReadDump(s);

View File

@ -1408,11 +1408,103 @@ void GetDateTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
st->wMilliseconds); st->wMilliseconds);
} }
// Convert string RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) to UINT64
UINT64 DateTimeStrRFC3339ToSystemTime64(char *str)
{
SYSTEMTIME st;
if (DateTimeStrRFC3339ToSystemTime(&st, str))
{
return SystemToUINT64(&st);
}
else
{
return 0;
}
}
// Convert string RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) to SYSTEMTIME
bool DateTimeStrRFC3339ToSystemTime(SYSTEMTIME *st, char *str)
{
bool ok = false;
UINT index_plus;
char tmp[MAX_PATH];
Zero(st, sizeof(SYSTEMTIME));
if (st == NULL || str == NULL)
{
return false;
}
StrCpy(tmp, sizeof(tmp), str);
index_plus = SearchStrEx(tmp, "+", 0, false);
if (index_plus != INFINITE)
{
tmp[index_plus] = 0;
}
if (StrLen(tmp) >= 19)
{
if (tmp[4] == '-' && tmp[7] == '-' && tmp[10] == 'T' && tmp[13] == ':' &&
tmp[16] == ':')
{
char str_year[16], str_month[16], str_day[16], str_hour[16], str_minute[16],
str_second[16], str_msec[16];
StrCpy(str_year, sizeof(str_year), tmp + 0);
str_year[4] = 0;
StrCpy(str_month, sizeof(str_month), tmp + 5);
str_month[2] = 0;
StrCpy(str_day, sizeof(str_day), tmp + 8);
str_day[2] = 0;
StrCpy(str_hour, sizeof(str_hour), tmp + 11);
str_hour[2] = 0;
StrCpy(str_minute, sizeof(str_minute), tmp + 14);
str_minute[2] = 0;
StrCpy(str_second, sizeof(str_second), tmp + 17);
str_second[2] = 0;
str_msec[0] = 0;
if (StrLen(tmp) >= 21 && tmp[19] == '.')
{
StrCpy(str_msec, sizeof(str_msec), tmp + 20);
str_msec[StrLen(tmp) - 21] = 0;
while (StrLen(str_msec) < 3)
{
StrCat(str_msec, sizeof(str_msec), "0");
}
str_msec[3] = 0;
}
st->wYear = ToInt(str_year);
st->wMonth = ToInt(str_month);
st->wDay = ToInt(str_day);
st->wHour = ToInt(str_hour);
st->wMinute = ToInt(str_minute);
st->wSecond = ToInt(str_second);
st->wMilliseconds = ToInt(str_msec);
NormalizeSystem(st);
ok = true;
}
}
return ok;
}
// Get the date and time string in RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) // Get the date and time string in RFC3339 format (example: 2017-09-27T18:25:55.434-9:00)
void GetDateTimeStrRFC3339(char *str, UINT size, SYSTEMTIME *st, int timezone_min){ void GetDateTimeStrRFC3339(char *str, UINT size, SYSTEMTIME *st, int timezone_min){
// Validate arguments // Validate arguments
if (str == NULL || st == NULL) if (str == NULL || st == NULL)
{ {
ClearStr(str, size);
return; return;
} }

View File

@ -137,6 +137,8 @@ void GetDateTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale);
void GetDateStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale); void GetDateStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale);
void GetTimeStrMilli64(char *str, UINT size, UINT64 sec64); void GetTimeStrMilli64(char *str, UINT size, UINT64 sec64);
void GetDateTimeStrRFC3339(char *str, UINT size, SYSTEMTIME *st, int timezone_min); void GetDateTimeStrRFC3339(char *str, UINT size, SYSTEMTIME *st, int timezone_min);
bool DateTimeStrRFC3339ToSystemTime(SYSTEMTIME *st, char *str);
UINT64 DateTimeStrRFC3339ToSystemTime64(char *str);
UINT64 SafeTime64(UINT64 sec64); UINT64 SafeTime64(UINT64 sec64);
bool Run(char *filename, char *arg, bool hide, bool wait); bool Run(char *filename, char *arg, bool hide, bool wait);
bool RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait); bool RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait);

View File

@ -347,6 +347,9 @@ typedef struct PRAND PRAND;
// Str.h // Str.h
typedef struct TOKEN_LIST TOKEN_LIST; typedef struct TOKEN_LIST TOKEN_LIST;
typedef struct INI_ENTRY INI_ENTRY; typedef struct INI_ENTRY INI_ENTRY;
typedef struct JSON_OBJECT JSON_OBJECT;
typedef struct JSON_ARRAY JSON_ARRAY;
typedef struct JSON_VALUE JSON_VALUE;
// Internat.h // Internat.h
typedef struct UNI_TOKEN_LIST UNI_TOKEN_LIST; typedef struct UNI_TOKEN_LIST UNI_TOKEN_LIST;
@ -383,6 +386,8 @@ typedef struct INSTANCE INSTANCE;
typedef struct VALUE VALUE; typedef struct VALUE VALUE;
typedef struct ELEMENT ELEMENT; typedef struct ELEMENT ELEMENT;
typedef struct PACK PACK; typedef struct PACK PACK;
typedef struct JSONPACKHINT JSONPACKHINT;
typedef struct JSONPACKHINT_ITEM JSONPACKHINT_ITEM;
// Cfg.h // Cfg.h
typedef struct FOLDER FOLDER; typedef struct FOLDER FOLDER;

View File

@ -1413,6 +1413,48 @@ bool ReplaceListPointer(LIST *o, void *oldptr, void *newptr)
return false; return false;
} }
// New string list
LIST *NewStrList()
{
return NewListFast(CompareStr);
}
// Release string list
void ReleaseStrList(LIST *o)
{
UINT i;
if (o == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(o);i++)
{
char *s = LIST_DATA(o, i);
Free(s);
}
ReleaseList(o);
}
// Add a string distinct to the string list
bool AddStrToStrListDistinct(LIST *o, char *str)
{
if (o == NULL || str == NULL)
{
return false;
}
if (IsInListStr(o, str) == false)
{
Add(o, CopyStr(str));
return true;
}
return false;
}
// Examine whether a string items are present in the list // Examine whether a string items are present in the list
bool IsInListStr(LIST *o, char *str) bool IsInListStr(LIST *o, char *str)
{ {
@ -2948,6 +2990,43 @@ void WriteBufBuf(BUF *b, BUF *bb)
WriteBuf(b, bb->Buf, bb->Size); WriteBuf(b, bb->Buf, bb->Size);
} }
// Write the buffer (from the offset) to a buffer
void WriteBufBufWithOffset(BUF *b, BUF *bb)
{
// Validate arguments
if (b == NULL || bb == NULL)
{
return;
}
WriteBuf(b, ((UCHAR *)bb->Buf) + bb->Current, bb->Size - bb->Current);
}
// Skip UTF-8 BOM
bool BufSkipUtf8Bom(BUF *b)
{
if (b == NULL)
{
return false;
}
SeekBufToBegin(b);
if (b->Size >= 3)
{
UCHAR *data = b->Buf;
if (data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF)
{
SeekBuf(b, 3, 1);
return true;
}
}
return false;
}
// Read into a buffer from the buffer // Read into a buffer from the buffer
BUF *ReadBufFromBuf(BUF *b, UINT size) BUF *ReadBufFromBuf(BUF *b, UINT size)
{ {

View File

@ -208,7 +208,9 @@ BUF *NewBufFromMemory(void *buf, UINT size);
void ClearBuf(BUF *b); void ClearBuf(BUF *b);
void WriteBuf(BUF *b, void *buf, UINT size); void WriteBuf(BUF *b, void *buf, UINT size);
void WriteBufBuf(BUF *b, BUF *bb); void WriteBufBuf(BUF *b, BUF *bb);
void WriteBufBufWithOffset(BUF *b, BUF *bb);
UINT ReadBuf(BUF *b, void *buf, UINT size); UINT ReadBuf(BUF *b, void *buf, UINT size);
bool BufSkipUtf8Bom(BUF *b);
BUF *ReadBufFromBuf(BUF *b, UINT size); BUF *ReadBufFromBuf(BUF *b, UINT size);
void AdjustBufSize(BUF *b, UINT new_size); void AdjustBufSize(BUF *b, UINT new_size);
void SeekBuf(BUF *b, UINT offset, int mode); void SeekBuf(BUF *b, UINT offset, int mode);
@ -357,5 +359,9 @@ void CleanupSharedBuffer(SHARED_BUFFER *b);
void AppendBufUtf8(BUF *b, wchar_t *str); void AppendBufUtf8(BUF *b, wchar_t *str);
void AppendBufStr(BUF *b, char *str); void AppendBufStr(BUF *b, char *str);
LIST *NewStrList();
void ReleaseStrList(LIST *o);
bool AddStrToStrListDistinct(LIST *o, char *str);
#endif // MEMORY_H #endif // MEMORY_H

View File

@ -7229,6 +7229,12 @@ bool IsIP4(IP *ip)
return (IsIP6(ip) ? false : true); return (IsIP6(ip) ? false : true);
} }
// Copy the IP address
void CopyIP(IP *dst, IP *src)
{
Copy(dst, src, sizeof(IP));
}
// Get the number of clients connected from the specified IP address // Get the number of clients connected from the specified IP address
UINT GetNumIpClient(IP *ip) UINT GetNumIpClient(IP *ip)
{ {
@ -11368,6 +11374,50 @@ void InitSockSet(SOCKSET *set)
Zero(set, sizeof(SOCKSET)); Zero(set, sizeof(SOCKSET));
} }
// Receive data and discard all of them
bool RecvAllWithDiscard(SOCK *sock, UINT size, bool secure)
{
static UCHAR buffer[4096];
UINT recv_size, sz, ret;
if (sock == NULL)
{
return false;
}
if (size == 0)
{
return true;
}
if (sock->AsyncMode)
{
return false;
}
recv_size = 0;
while (true)
{
sz = MIN(size - recv_size, sizeof(buffer));
ret = Recv(sock, buffer, sz, secure);
if (ret == 0)
{
return false;
}
if (ret == SOCK_LATER)
{
// I suppose that this is safe because the RecvAll() function is used only
// if the sock->AsyncMode == true. And the Recv() function may return
// SOCK_LATER only if the sock->AsyncMode == false. Therefore the call of
// Recv() function in the RecvAll() function never returns SOCK_LATER.
return false;
}
recv_size += ret;
if (recv_size >= size)
{
return true;
}
}
}
// Receive all by TCP // Receive all by TCP
bool RecvAll(SOCK *sock, void *data, UINT size, bool secure) bool RecvAll(SOCK *sock, void *data, UINT size, bool secure)
{ {

View File

@ -953,6 +953,7 @@ UINT GetContentLength(HTTP_HEADER *header);
void GetHttpDateStr(char *str, UINT size, UINT64 t); void GetHttpDateStr(char *str, UINT size, UINT64 t);
bool HttpSendForbidden(SOCK *s, char *target, char *server_id); bool HttpSendForbidden(SOCK *s, char *target, char *server_id);
bool HttpSendNotFound(SOCK *s, char *target); bool HttpSendNotFound(SOCK *s, char *target);
bool HttpSendBody(SOCK *s, void *data, UINT size, char *contents_type);
bool HttpSendNotImplemented(SOCK *s, char *method, char *target, char *version); bool HttpSendNotImplemented(SOCK *s, char *method, char *target, char *version);
bool HttpServerSend(SOCK *s, PACK *p); bool HttpServerSend(SOCK *s, PACK *p);
bool HttpClientSend(SOCK *s, PACK *p); bool HttpClientSend(SOCK *s, PACK *p);
@ -1193,6 +1194,7 @@ void SendAdd(SOCK *sock, void *data, UINT size);
bool SendNow(SOCK *sock, int secure); bool SendNow(SOCK *sock, int secure);
bool RecvAll(SOCK *sock, void *data, UINT size, bool secure); bool RecvAll(SOCK *sock, void *data, UINT size, bool secure);
bool RecvAllEx(SOCK *sock, void **data_new_ptr, UINT size, bool secure); bool RecvAllEx(SOCK *sock, void **data_new_ptr, UINT size, bool secure);
bool RecvAllWithDiscard(SOCK *sock, UINT size, bool secure);
void InitSockSet(SOCKSET *set); void InitSockSet(SOCKSET *set);
void AddSockSet(SOCKSET *set, SOCK *sock); void AddSockSet(SOCKSET *set, SOCK *sock);
CANCEL *NewCancel(); CANCEL *NewCancel();
@ -1308,6 +1310,7 @@ void SocketTimeoutThread(THREAD *t, void *param);
SOCKET_TIMEOUT_PARAM *NewSocketTimeout(SOCK *sock); SOCKET_TIMEOUT_PARAM *NewSocketTimeout(SOCK *sock);
void FreeSocketTimeout(SOCKET_TIMEOUT_PARAM *ttp); void FreeSocketTimeout(SOCKET_TIMEOUT_PARAM *ttp);
void CopyIP(IP *dst, IP *src);
bool IsIP6(IP *ip); bool IsIP6(IP *ip);
bool IsIP4(IP *ip); bool IsIP4(IP *ip);
void IPv6AddrToIP(IP *ip, IPV6_ADDR *addr); void IPv6AddrToIP(IP *ip, IPV6_ADDR *addr);

File diff suppressed because it is too large Load Diff

View File

@ -55,12 +55,38 @@ struct ELEMENT
UINT num_value; // Number of values (>=1) UINT num_value; // Number of values (>=1)
UINT type; // Type UINT type; // Type
VALUE **values; // List of pointers to the value VALUE **values; // List of pointers to the value
bool JsonHint_IsArray;
bool JsonHint_IsBool;
bool JsonHint_IsDateTime;
bool JsonHint_IsIP;
char JsonHint_GroupName[MAX_ELEMENT_NAME_LEN + 1];
}; };
// PACK object // PACK object
struct PACK struct PACK
{ {
LIST *elements; // Element list LIST *elements; // Element list
LIST *json_subitem_names; // JSON sub-item names
char CurrentJsonHint_GroupName[MAX_ELEMENT_NAME_LEN + 1];
};
#define MAX_JSONPACK_HINT_ITEMS 64
#define JSONPACK_HINT_TYPE_ARRAY 1
// JSON/PACK converter hint element
struct JSONPACKHINT_ITEM
{
UINT Type;
char ArrayNumNameInPack[MAX_ELEMENT_NAME_LEN + 1];
char ArrayMembersInPack[MAX_SIZE + 1];
};
// JSON/PACK converter hint
struct JSONPACKHINT
{
UINT NumHints;
JSONPACKHINT_ITEM Hints[MAX_JSONPACK_HINT_ITEMS];
}; };
@ -100,21 +126,23 @@ TOKEN_LIST *GetPackElementNames(PACK *p);
X *PackGetX(PACK *p, char *name); X *PackGetX(PACK *p, char *name);
K *PackGetK(PACK *p, char *name); K *PackGetK(PACK *p, char *name);
void PackAddX(PACK *p, char *name, X *x); ELEMENT *PackAddX(PACK *p, char *name, X *x);
void PackAddK(PACK *p, char *name, K *k); ELEMENT *PackAddK(PACK *p, char *name, K *k);
void PackAddStr(PACK *p, char *name, char *str); ELEMENT *PackAddStr(PACK *p, char *name, char *str);
void PackAddStrEx(PACK *p, char *name, char *str, UINT index, UINT total); ELEMENT *PackAddStrEx(PACK *p, char *name, char *str, UINT index, UINT total);
void PackAddUniStr(PACK *p, char *name, wchar_t *unistr); ELEMENT *PackAddUniStr(PACK *p, char *name, wchar_t *unistr);
void PackAddUniStrEx(PACK *p, char *name, wchar_t *unistr, UINT index, UINT total); ELEMENT *PackAddUniStrEx(PACK *p, char *name, wchar_t *unistr, UINT index, UINT total);
void PackAddInt(PACK *p, char *name, UINT i); ELEMENT *PackAddInt(PACK *p, char *name, UINT i);
void PackAddNum(PACK *p, char *name, UINT num); ELEMENT *PackAddNum(PACK *p, char *name, UINT num);
void PackAddIntEx(PACK *p, char *name, UINT i, UINT index, UINT total); ELEMENT *PackAddIntEx(PACK *p, char *name, UINT i, UINT index, UINT total);
void PackAddInt64(PACK *p, char *name, UINT64 i); ELEMENT *PackAddInt64(PACK *p, char *name, UINT64 i);
void PackAddInt64Ex(PACK *p, char *name, UINT64 i, UINT index, UINT total); ELEMENT *PackAddInt64Ex(PACK *p, char *name, UINT64 i, UINT index, UINT total);
void PackAddData(PACK *p, char *name, void *data, UINT size); ELEMENT *PackAddTime64(PACK *p, char *name, UINT64 i);
void PackAddDataEx(PACK *p, char *name, void *data, UINT size, UINT index, UINT total); ELEMENT *PackAddTime64Ex(PACK *p, char *name, UINT64 i, UINT index, UINT total);
void PackAddBuf(PACK *p, char *name, BUF *b); ELEMENT *PackAddData(PACK *p, char *name, void *data, UINT size);
void PackAddBufEx(PACK *p, char *name, BUF *b, UINT index, UINT total); ELEMENT *PackAddDataEx(PACK *p, char *name, void *data, UINT size, UINT index, UINT total);
ELEMENT *PackAddBuf(PACK *p, char *name, BUF *b);
ELEMENT *PackAddBufEx(PACK *p, char *name, BUF *b, UINT index, UINT total);
bool PackGetStr(PACK *p, char *name, char *str, UINT size); bool PackGetStr(PACK *p, char *name, char *str, UINT size);
bool PackGetStrEx(PACK *p, char *name, char *str, UINT size, UINT index); bool PackGetStrEx(PACK *p, char *name, char *str, UINT size, UINT index);
bool PackGetUniStr(PACK *p, char *name, wchar_t *unistr, UINT size); bool PackGetUniStr(PACK *p, char *name, wchar_t *unistr, UINT size);
@ -133,23 +161,38 @@ bool PackGetDataEx(PACK *p, char *name, void *data, UINT index);
BUF *PackGetBuf(PACK *p, char *name); BUF *PackGetBuf(PACK *p, char *name);
BUF *PackGetBufEx(PACK *p, char *name, UINT index); BUF *PackGetBufEx(PACK *p, char *name, UINT index);
bool PackGetBool(PACK *p, char *name); bool PackGetBool(PACK *p, char *name);
void PackAddBool(PACK *p, char *name, bool b); ELEMENT *PackAddBool(PACK *p, char *name, bool b);
void PackAddBoolEx(PACK *p, char *name, bool b, UINT index, UINT total); ELEMENT *PackAddBoolEx(PACK *p, char *name, bool b, UINT index, UINT total);
bool PackGetBoolEx(PACK *p, char *name, UINT index); bool PackGetBoolEx(PACK *p, char *name, UINT index);
void PackAddIp(PACK *p, char *name, IP *ip); void PackAddIp(PACK *p, char *name, IP *ip);
void PackAddIpEx(PACK *p, char *name, IP *ip, UINT index, UINT total); void PackAddIpEx(PACK *p, char *name, IP *ip, UINT index, UINT total);
void PackAddIpEx2(PACK *p, char *name, IP *ip, UINT index, UINT total, bool is_single);
bool PackGetIp(PACK *p, char *name, IP *ip); bool PackGetIp(PACK *p, char *name, IP *ip);
bool PackGetIpEx(PACK *p, char *name, IP *ip, UINT index); bool PackGetIpEx(PACK *p, char *name, IP *ip, UINT index);
UINT PackGetIp32(PACK *p, char *name); UINT PackGetIp32(PACK *p, char *name);
UINT PackGetIp32Ex(PACK *p, char *name, UINT index); UINT PackGetIp32Ex(PACK *p, char *name, UINT index);
void PackAddIp32(PACK *p, char *name, UINT ip32); void PackAddIp32(PACK *p, char *name, UINT ip32);
void PackAddIp32Ex(PACK *p, char *name, UINT ip32, UINT index, UINT total); void PackAddIp32Ex(PACK *p, char *name, UINT ip32, UINT index, UINT total);
void PackAddIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index, UINT total); void PackAddIp32Ex2(PACK *p, char *name, UINT ip32, UINT index, UINT total, bool is_single);
ELEMENT *PackAddIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index, UINT total);
bool PackGetIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index); bool PackGetIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index);
void PackAddIp6Addr(PACK *p, char *name, IPV6_ADDR *addr); ELEMENT *PackAddIp6Addr(PACK *p, char *name, IPV6_ADDR *addr);
bool PackGetIp6Addr(PACK *p, char *name, IPV6_ADDR *addr); bool PackGetIp6Addr(PACK *p, char *name, IPV6_ADDR *addr);
bool PackGetData2(PACK *p, char *name, void *data, UINT size); bool PackGetData2(PACK *p, char *name, void *data, UINT size);
bool PackGetDataEx2(PACK *p, char *name, void *data, UINT size, UINT index); bool PackGetDataEx2(PACK *p, char *name, void *data, UINT size, UINT index);
bool PackIsValueExists(PACK *p, char *name); bool PackIsValueExists(PACK *p, char *name);
void PackSetCurrentJsonGroupName(PACK *p, char *json_group_name);
ELEMENT *ElementNullSafe(ELEMENT *p);
JSON_VALUE *PackToJson(PACK *p);
char *PackToJsonStr(PACK *p);
PACK *JsonToPack(JSON_VALUE *v);
PACK *JsonStrToPack(char *str);
void PackArrayElementToJsonArray(JSON_ARRAY *ja, PACK *p, ELEMENT *e, UINT index);
void PackElementToJsonObject(JSON_OBJECT *o, PACK *p, ELEMENT *e, UINT index);
char *DetermineJsonSuffixForPackElement(ELEMENT *e);
bool JsonTryParseValueAddToPack(PACK *p, JSON_VALUE *v, char *v_name, UINT index, UINT total, bool is_single);
#endif // PACK_H #endif // PACK_H

File diff suppressed because it is too large Load Diff

View File

@ -79,7 +79,9 @@ void BinToStrW(wchar_t *str, UINT str_size, void *data, UINT data_size);
void PrintBin(void *data, UINT size); void PrintBin(void *data, UINT size);
bool StartWith(char *str, char *key); bool StartWith(char *str, char *key);
bool EndWith(char *str, char *key); bool EndWith(char *str, char *key);
bool TrimEndWith(char *dst, UINT dst_size, char *str, char *key);
UINT64 ToInt64(char *str); UINT64 ToInt64(char *str);
UINT64 Json_ToInt64Ex(char *str, char **endptr, bool *error);
void ToStr64(char *str, UINT64 value); void ToStr64(char *str, UINT64 value);
TOKEN_LIST *ParseCmdLine(char *str); TOKEN_LIST *ParseCmdLine(char *str);
TOKEN_LIST *CopyToken(TOKEN_LIST *src); TOKEN_LIST *CopyToken(TOKEN_LIST *src);
@ -128,6 +130,259 @@ LIST *StrToIntList(char *str, bool sorted);
void NormalizeIntListStr(char *dst, UINT dst_size, char *src, bool sorted, char *separate_str); void NormalizeIntListStr(char *dst, UINT dst_size, char *src, bool sorted, char *separate_str);
void ClearStr(char *str, UINT str_size); void ClearStr(char *str, UINT str_size);
void SetStrCaseAccordingToBits(char *str, UINT bits); void SetStrCaseAccordingToBits(char *str, UINT bits);
char *UrlDecode(char *url_str);
// *** JSON strings support
// Original source code from Parson ( http://kgabis.github.com/parson/ )
// Modified by dnobori
/*
Parson ( http://kgabis.github.com/parson/ )
Copyright (c) 2012 - 2017 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Type definitions */
typedef union JSON_VALUE_UNION {
char *string;
UINT64 number;
JSON_OBJECT *object;
JSON_ARRAY *array;
int boolean;
int null;
} JSON_VALUE_UNION;
struct JSON_VALUE {
JSON_VALUE *parent;
UINT type;
JSON_VALUE_UNION value;
};
struct JSON_OBJECT {
JSON_VALUE *wrapping_value;
char **names;
JSON_VALUE **values;
UINT count;
UINT capacity;
};
struct JSON_ARRAY {
JSON_VALUE *wrapping_value;
JSON_VALUE **items;
UINT count;
UINT capacity;
};
enum JSON_TYPES {
JSON_TYPE_ERROR = -1,
JSON_TYPE_NULL = 1,
JSON_TYPE_STRING = 2,
JSON_TYPE_NUMBER = 3,
JSON_TYPE_OBJECT = 4,
JSON_TYPE_ARRAY = 5,
JSON_TYPE_BOOL = 6
};
typedef unsigned int UINT;
enum JSON_RETS {
JSON_RET_OK = 0,
JSON_RET_ERROR = -1
};
typedef void * (*JSON_Malloc_Function)(UINT);
typedef void(*JSON_Free_Function)(void *);
/* Call only once, before calling any other function from parson API. If not called, malloc and free
from stdlib will be used for all allocations */
void JsonSetAllocationFunctions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
/* Parses first JSON value in a string, returns NULL in case of error */
JSON_VALUE * JsonParseString(char *string);
/* Parses first JSON value in a string and ignores comments (/ * * / and //),
returns NULL in case of error */
JSON_VALUE * JsonParseStringWithComments(char *string);
/* Serialization */
UINT JsonGetSerializationSize(JSON_VALUE *value); /* returns 0 on fail */
UINT JsonSerializeToBuffer(JSON_VALUE *value, char *buf, UINT buf_size_in_bytes);
char * JsonSerializeToString(JSON_VALUE *value);
/* Pretty serialization */
UINT JsonGetSerializationSizePretty(JSON_VALUE *value); /* returns 0 on fail */
UINT JsonSerializeToBufferPretty(JSON_VALUE *value, char *buf, UINT buf_size_in_bytes);
char * JsonSerializeToStringPretty(JSON_VALUE *value);
char *JsonToStr(JSON_VALUE *v);
void JsonFreeString(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
/* Comparing */
int JsonCmp(JSON_VALUE *a, JSON_VALUE *b);
/* Validation
This is *NOT* JSON Schema. It validates json by checking if object have identically
named fields with matching types.
For example schema {"name":"", "age":0} will validate
{"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
In case of arrays, only first value in schema is checked against all values in tested array.
Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays,
null validates values of every type.
*/
UINT JsonValidate(JSON_VALUE *schema, JSON_VALUE *value);
/*
* JSON Object
*/
JSON_VALUE * JsonGet(JSON_OBJECT *object, char *name);
char * JsonGetStr(JSON_OBJECT *object, char *name);
JSON_OBJECT * JsonGetObj(JSON_OBJECT *object, char *name);
JSON_ARRAY * JsonGetArray(JSON_OBJECT *object, char *name);
UINT64 JsonGetNumber(JSON_OBJECT *object, char *name); /* returns 0 on fail */
bool JsonGetBool(JSON_OBJECT *object, char *name); /* returns 0 on fail */
/* dotget functions enable addressing values with dot notation in nested objects,
just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
Because valid names in JSON can contain dots, some values may be inaccessible
this way. */
JSON_VALUE * JsonDotGet(JSON_OBJECT *object, char *name);
char * JsonDotGetStr(JSON_OBJECT *object, char *name);
JSON_OBJECT * JsonDotGetObj(JSON_OBJECT *object, char *name);
JSON_ARRAY * JsonDotGetArray(JSON_OBJECT *object, char *name);
UINT64 JsonDotGetNumber(JSON_OBJECT *object, char *name); /* returns 0 on fail */
bool JsonDotGetBool(JSON_OBJECT *object, char *name); /* returns -1 on fail */
/* Functions to get available names */
UINT JsonGetCount(JSON_OBJECT *object);
char * JsonGetName(JSON_OBJECT *object, UINT index);
JSON_VALUE * JsonGetValueAt(JSON_OBJECT *object, UINT index);
JSON_VALUE * JsonGetWrappingValue(JSON_OBJECT *object);
/* Functions to check if object has a value with a specific name. Returned value is 1 if object has
* a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */
int JsonIsExists(JSON_OBJECT *object, char *name);
int JsonIsExistsWithValueType(JSON_OBJECT *object, char *name, UINT type);
int JsonDotIsExists(JSON_OBJECT *object, char *name);
int JsonDotIsExistsWithValueType(JSON_OBJECT *object, char *name, UINT type);
/* Creates new name-value pair or frees and replaces old value with a new one.
* json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
UINT JsonSet(JSON_OBJECT *object, char *name, JSON_VALUE *value);
UINT JsonSetStr(JSON_OBJECT *object, char *name, char *string);
UINT JsonSetUniStr(JSON_OBJECT *object, char *name, wchar_t *string);
UINT JsonSetNumber(JSON_OBJECT *object, char *name, UINT64 number);
UINT JsonSetBool(JSON_OBJECT *object, char *name, int boolean);
UINT JsonSetNull(JSON_OBJECT *object, char *name);
UINT JsonSetData(JSON_OBJECT *object, char *name, void *data, UINT size);
/* Works like dotget functions, but creates whole hierarchy if necessary.
* json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
UINT JsonDotSet(JSON_OBJECT *object, char *name, JSON_VALUE *value);
UINT JsonDotSetStr(JSON_OBJECT *object, char *name, char *string);
UINT JsonDotSetNumber(JSON_OBJECT *object, char *name, UINT64 number);
UINT JsonDotSetBool(JSON_OBJECT *object, char *name, int boolean);
UINT JsonDotSetNull(JSON_OBJECT *object, char *name);
/* Frees and removes name-value pair */
UINT JsonDelete(JSON_OBJECT *object, char *name);
/* Works like dotget function, but removes name-value pair only on exact match. */
UINT JsonDotDelete(JSON_OBJECT *object, char *key);
/* Removes all name-value pairs in object */
UINT JsonDeleteAll(JSON_OBJECT *object);
/*
*JSON Array
*/
JSON_VALUE * JsonArrayGet(JSON_ARRAY *array, UINT index);
char * JsonArrayGetStr(JSON_ARRAY *array, UINT index);
JSON_OBJECT * JsonArrayGetObj(JSON_ARRAY *array, UINT index);
JSON_ARRAY * JsonArrayGetArray(JSON_ARRAY *array, UINT index);
UINT64 JsonArrayGetNumber(JSON_ARRAY *array, UINT index); /* returns 0 on fail */
bool JsonArrayGetBool(JSON_ARRAY *array, UINT index); /* returns 0 on fail */
UINT JsonArrayGetCount(JSON_ARRAY *array);
JSON_VALUE * JsonArrayGetWrappingValue(JSON_ARRAY *array);
/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
* Order of values in array may change during execution. */
UINT JsonArrayDelete(JSON_ARRAY *array, UINT i);
/* Frees and removes from array value at given index and replaces it with given one.
* Does nothing and returns JSONFailure if index doesn't exist.
* json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
UINT JsonArrayReplace(JSON_ARRAY *array, UINT i, JSON_VALUE *value);
UINT JsonArrayReplaceStr(JSON_ARRAY *array, UINT i, char* string);
UINT JsonArrayReplaceNumber(JSON_ARRAY *array, UINT i, UINT64 number);
UINT JsonArrayReplaceBool(JSON_ARRAY *array, UINT i, int boolean);
UINT JsonArrayReplaceNull(JSON_ARRAY *array, UINT i);
/* Frees and removes all values from array */
UINT JsonArrayDeleteAll(JSON_ARRAY *array);
/* Appends new value at the end of array.
* json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
UINT JsonArrayAdd(JSON_ARRAY *array, JSON_VALUE *value);
UINT JsonArrayAddStr(JSON_ARRAY *array, char *string);
UINT JsonArrayAddUniStr(JSON_ARRAY *array, wchar_t *string);
UINT JsonArrayAddNumber(JSON_ARRAY *array, UINT64 number);
UINT JsonArrayAddData(JSON_ARRAY *array, void *data, UINT size);
UINT JsonArrayAddBool(JSON_ARRAY *array, int boolean);
UINT JsonArrayAddNull(JSON_ARRAY *array);
/*
*JSON Value
*/
JSON_VALUE * JsonNewObject(void);
JSON_VALUE * JsonNewArray(void);
JSON_VALUE * JsonNewStr(char *string); /* copies passed string */
JSON_VALUE * JsonNewNumber(UINT64 number);
JSON_VALUE * JsonNewBool(int boolean);
JSON_VALUE * JsonNewNull(void);
JSON_VALUE * JsonDeepCopy(JSON_VALUE *value);
void JsonFree(JSON_VALUE *value);
UINT JsonValueGetType(JSON_VALUE *value);
JSON_OBJECT * JsonValueGetObject(JSON_VALUE *value);
JSON_ARRAY * JsonValueGetArray(JSON_VALUE *value);
char * JsonValueGetStr(JSON_VALUE *value);
UINT64 JsonValueGetNumber(JSON_VALUE *value);
bool JsonValueGetBool(JSON_VALUE *value);
JSON_VALUE * JsonValueGetParent(JSON_VALUE *value);
/* Same as above, but shorter */
UINT JsonType(JSON_VALUE *value);
JSON_OBJECT * JsonObject(JSON_VALUE *value);
JSON_ARRAY * JsonArray(JSON_VALUE *value);
char * JsonString(JSON_VALUE *value);
UINT64 JsonNumber(JSON_VALUE *value);
int JsonBool(JSON_VALUE *value);
void SystemTimeToJsonStr(char *dst, UINT size, SYSTEMTIME *t);
void SystemTime64ToJsonStr(char *dst, UINT size, UINT64 t);
JSON_VALUE *StrToJson(char *str);
#endif // STR_H #endif // STR_H