xref: /petsc/src/sys/webclient/client.c (revision 37fdd0055130c7e84fc09516fb012d75c18be859)
1b967cddfSBarry Smith 
20efc6a03SBarry Smith #include <petscwebclient.h>
31c7e414eSJacob Faibussowitsch PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wdeprecated-declarations")
4b967cddfSBarry Smith 
5b967cddfSBarry Smith static BIO *bio_err = NULL;
6b967cddfSBarry Smith 
7b967cddfSBarry Smith #define PASSWORD "password"
8b967cddfSBarry Smith 
94a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
10d71ae5a4SJacob Faibussowitsch static int password_cb(char *buf, int num, int rwflag, void *userdata)
11d71ae5a4SJacob Faibussowitsch {
12b967cddfSBarry Smith   if (num < strlen(PASSWORD) + 1) return (0);
13b967cddfSBarry Smith   strcpy(buf, PASSWORD);
14b967cddfSBarry Smith   return (strlen(PASSWORD));
15b967cddfSBarry Smith }
16b967cddfSBarry Smith #endif
17b967cddfSBarry Smith 
189371c9d4SSatish Balay static void sigpipe_handle(int x) { }
19b967cddfSBarry Smith 
204683183fSBarry Smith /*@C
21b967cddfSBarry Smith     PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
22b967cddfSBarry Smith 
234683183fSBarry Smith     Output Parameter:
24811af0c4SBarry Smith .   octx - the SSL_CTX to be passed to `PetscHTTPSConnect90`
25b967cddfSBarry Smith 
264683183fSBarry Smith     Level: advanced
274683183fSBarry Smith 
284683183fSBarry Smith     If PETSc was ./configure -with-ssl-certificate requires the user have created a self-signed certificate with
29*37fdd005SBarry Smith .vb
30*37fdd005SBarry Smith     saws/CA.pl  -newcert  (using the passphrase of password)
31*37fdd005SBarry Smith     cat newkey.pem newcert.pem > sslclient.pem
32*37fdd005SBarry Smith .ve
33b967cddfSBarry Smith 
34b967cddfSBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
35b967cddfSBarry Smith     silly but it was all I could figure out.
36b967cddfSBarry Smith 
37db781477SPatrick Sanan .seealso: `PetscSSLDestroyContext()`, `PetscHTTPSConnect()`, `PetscHTTPSRequest()`
384683183fSBarry Smith @*/
39d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
40d71ae5a4SJacob Faibussowitsch {
41b967cddfSBarry Smith   SSL_CTX *ctx;
424a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
43b967cddfSBarry Smith   char      keyfile[PETSC_MAX_PATH_LEN];
44b967cddfSBarry Smith   PetscBool exists;
45b967cddfSBarry Smith #endif
46b967cddfSBarry Smith 
47b967cddfSBarry Smith   PetscFunctionBegin;
48b967cddfSBarry Smith   if (!bio_err) {
49b967cddfSBarry Smith     SSL_library_init();
50b967cddfSBarry Smith     SSL_load_error_strings();
51b967cddfSBarry Smith     bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
52b967cddfSBarry Smith   }
53b967cddfSBarry Smith 
54b967cddfSBarry Smith   /* Set up a SIGPIPE handler */
55b967cddfSBarry Smith   signal(SIGPIPE, sigpipe_handle);
56b967cddfSBarry Smith 
57ecd1d7b8SBarry Smith /* suggested at https://mta.openssl.org/pipermail/openssl-dev/2015-May/001449.html */
58ecd1d7b8SBarry Smith #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
59ecd1d7b8SBarry Smith   ctx = SSL_CTX_new(TLS_client_method());
60ecd1d7b8SBarry Smith #else
61ecd1d7b8SBarry Smith   ctx = SSL_CTX_new(SSLv23_client_method());
62ecd1d7b8SBarry Smith #endif
635dc0f0a4SBarry Smith   SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
64b967cddfSBarry Smith 
654a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
66b967cddfSBarry Smith   /* Locate keyfile */
67c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(keyfile, "sslclient.pem", sizeof(keyfile)));
689566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(keyfile, 'r', &exists));
69b967cddfSBarry Smith   if (!exists) {
709566063dSJacob Faibussowitsch     PetscCall(PetscGetHomeDirectory(keyfile, PETSC_MAX_PATH_LEN));
71c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "/", sizeof(keyfile)));
72c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "sslclient.pem", sizeof(keyfile)));
739566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(keyfile, 'r', &exists));
7428b400f6SJacob Faibussowitsch     PetscCheck(exists, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate sslclient.pem file in current directory or home directory");
75b967cddfSBarry Smith   }
76b967cddfSBarry Smith 
77b967cddfSBarry Smith   /* Load our keys and certificates*/
78cc73adaaSBarry Smith   PetscCheck(SSL_CTX_use_certificate_chain_file(ctx, keyfile), PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot read certificate file");
79b967cddfSBarry Smith 
80b967cddfSBarry Smith   SSL_CTX_set_default_passwd_cb(ctx, password_cb);
81cc73adaaSBarry Smith   PetscCheck(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM), PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot read key file");
82b967cddfSBarry Smith #endif
83b967cddfSBarry Smith 
84b967cddfSBarry Smith   *octx = ctx;
853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
86b967cddfSBarry Smith }
87b967cddfSBarry Smith 
884683183fSBarry Smith /*@C
89811af0c4SBarry Smith      PetscSSLDestroyContext - frees a `SSL_CTX` obtained with `PetscSSLInitializeContext()`
904683183fSBarry Smith 
914683183fSBarry Smith      Input Parameter:
92811af0c4SBarry Smith .     ctx - the `SSL_CTX`
934683183fSBarry Smith 
944683183fSBarry Smith     Level: advanced
954683183fSBarry Smith 
96db781477SPatrick Sanan .seealso: `PetscSSLInitializeContext()`, `PetscHTTPSConnect()`
974683183fSBarry Smith @*/
98d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
99d71ae5a4SJacob Faibussowitsch {
100b967cddfSBarry Smith   PetscFunctionBegin;
101b967cddfSBarry Smith   SSL_CTX_free(ctx);
1023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103b967cddfSBarry Smith }
104b967cddfSBarry Smith 
105d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscHTTPBuildRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], char **outrequest)
106d71ae5a4SJacob Faibussowitsch {
107b967cddfSBarry Smith   char     *request = 0;
10893e1d32fSBarry Smith   char      contentlength[40], contenttype[80], *path, *host;
1097a3410edSBarry Smith   size_t    request_len, headlen, bodylen, contentlen, pathlen, hostlen, typelen, contenttypelen = 0;
110b967cddfSBarry Smith   PetscBool flg;
111b967cddfSBarry Smith 
112b967cddfSBarry Smith   PetscFunctionBegin;
1139566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(url, &host));
1149566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(host, '/', &path));
11528b400f6SJacob Faibussowitsch   PetscCheck(path, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "url must contain / it is %s", url);
116c245270aSBarry Smith   *path = 0;
1179566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(host, &hostlen));
11893e1d32fSBarry Smith 
1199566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(url, '/', &path));
1209566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(path, &pathlen));
12193e1d32fSBarry Smith 
122b967cddfSBarry Smith   if (header) {
1239566063dSJacob Faibussowitsch     PetscCall(PetscStrendswith(header, "\r\n", &flg));
124d8174014SToby Isaac     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "header must end with \\r\\n");
125b967cddfSBarry Smith   }
126b967cddfSBarry Smith 
1279566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(type, &typelen));
128b967cddfSBarry Smith   if (ctype) {
1299566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(contenttype, 80, "Content-Type: %s\r\n", ctype));
1309566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(contenttype, &contenttypelen));
131b967cddfSBarry Smith   }
1329566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(header, &headlen));
1339566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(body, &bodylen));
1349566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(contentlength, 40, "Content-Length: %d\r\n\r\n", (int)bodylen));
1359566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(contentlength, &contentlen));
136b967cddfSBarry Smith 
137b967cddfSBarry Smith   /* Now construct our HTTP request */
13893e1d32fSBarry Smith   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
1399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(request_len, &request));
140c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(request, type, request_len));
141c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, " ", request_len));
142c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, path, request_len));
143c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, " HTTP/1.1\r\nHost: ", request_len));
144c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, host, request_len));
1459566063dSJacob Faibussowitsch   PetscCall(PetscFree(host));
146c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, "\r\nUser-Agent:PETScClient\r\n", request_len));
147c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, header, request_len));
148c6a7a370SJeremy L Thompson   if (ctype) PetscCall(PetscStrlcat(request, contenttype, request_len));
149c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, contentlength, request_len));
150c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, body, request_len));
1519566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
1529566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTPS request follows: \n%s\n", request));
153b967cddfSBarry Smith 
15404102261SBarry Smith   *outrequest = request;
1553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15604102261SBarry Smith }
15704102261SBarry Smith 
1584683183fSBarry Smith /*@C
15904102261SBarry Smith      PetscHTTPSRequest - Send a request to an HTTPS server
16004102261SBarry Smith 
16104102261SBarry Smith    Input Parameters:
16204102261SBarry Smith +   type - either "POST" or "GET"
16304102261SBarry Smith .   url -  URL of request host/path
16404102261SBarry Smith .   header - additional header information, may be NULL
16504102261SBarry Smith .   ctype - data type of body, for example application/json
16604102261SBarry Smith .   body - data to send to server
167811af0c4SBarry Smith .   ssl - obtained with `PetscHTTPSConnect()`
16804102261SBarry Smith -   buffsize - size of buffer
16904102261SBarry Smith 
17004102261SBarry Smith    Output Parameter:
17104102261SBarry Smith .   buff - everything returned from server
1724683183fSBarry Smith 
1734683183fSBarry Smith     Level: advanced
1744683183fSBarry Smith 
175db781477SPatrick Sanan .seealso: `PetscHTTPRequest()`, `PetscHTTPSConnect()`, `PetscSSLInitializeContext()`, `PetscSSLDestroyContext()`, `PetscPullJSONValue()`
1764683183fSBarry Smith @*/
177d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHTTPSRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], SSL *ssl, char buff[], size_t buffsize)
178d71ae5a4SJacob Faibussowitsch {
17904102261SBarry Smith   char     *request;
18004102261SBarry Smith   int       r;
18104102261SBarry Smith   size_t    request_len, len;
1825dc0f0a4SBarry Smith   PetscBool foundbody = PETSC_FALSE;
18304102261SBarry Smith 
18404102261SBarry Smith   PetscFunctionBegin;
1859566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type, url, header, ctype, body, &request));
1869566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
18704102261SBarry Smith 
188d8dcb26dSBarry Smith   r = SSL_write(ssl, request, (int)request_len);
189b967cddfSBarry Smith   switch (SSL_get_error(ssl, r)) {
190d71ae5a4SJacob Faibussowitsch   case SSL_ERROR_NONE:
191d71ae5a4SJacob Faibussowitsch     PetscCheck(request_len == (size_t)r, PETSC_COMM_SELF, PETSC_ERR_LIB, "Incomplete write to SSL socket");
192d71ae5a4SJacob Faibussowitsch     break;
193d71ae5a4SJacob Faibussowitsch   default:
194d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL socket write problem");
195b967cddfSBarry Smith   }
196b967cddfSBarry Smith 
1975dc0f0a4SBarry Smith   /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
1989566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(buff, buffsize));
1995dc0f0a4SBarry Smith   len       = 0;
2005dc0f0a4SBarry Smith   foundbody = PETSC_FALSE;
2015dc0f0a4SBarry Smith   do {
2025dc0f0a4SBarry Smith     char  *clen;
2035dc0f0a4SBarry Smith     int    cl;
2045dc0f0a4SBarry Smith     size_t nlen;
2055dc0f0a4SBarry Smith 
2065dc0f0a4SBarry Smith     r = SSL_read(ssl, buff + len, (int)buffsize);
2075dc0f0a4SBarry Smith     len += r;
208b967cddfSBarry Smith     switch (SSL_get_error(ssl, r)) {
209d71ae5a4SJacob Faibussowitsch     case SSL_ERROR_NONE:
210d71ae5a4SJacob Faibussowitsch       break;
211b967cddfSBarry Smith     case SSL_ERROR_ZERO_RETURN:
2125dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2135dc0f0a4SBarry Smith       SSL_shutdown(ssl);
214b967cddfSBarry Smith       break;
215d71ae5a4SJacob Faibussowitsch     case SSL_ERROR_SYSCALL:
216d71ae5a4SJacob Faibussowitsch       foundbody = PETSC_TRUE;
217d71ae5a4SJacob Faibussowitsch       break;
218d71ae5a4SJacob Faibussowitsch     default:
219d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL read problem");
220b967cddfSBarry Smith     }
2215dc0f0a4SBarry Smith 
2229566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, "Content-Length: ", &clen));
2235dc0f0a4SBarry Smith     if (clen) {
2245dc0f0a4SBarry Smith       clen += 15;
2255dc0f0a4SBarry Smith       sscanf(clen, "%d", &cl);
2265dc0f0a4SBarry Smith       if (!cl) foundbody = PETSC_TRUE;
2275dc0f0a4SBarry Smith       else {
2289566063dSJacob Faibussowitsch         PetscCall(PetscStrstr(buff, "\r\n\r\n", &clen));
2295dc0f0a4SBarry Smith         if (clen) {
2309566063dSJacob Faibussowitsch           PetscCall(PetscStrlen(clen, &nlen));
2315dc0f0a4SBarry Smith           if (nlen - 4 == (size_t)cl) foundbody = PETSC_TRUE;
2325dc0f0a4SBarry Smith         }
2335dc0f0a4SBarry Smith       }
2345dc0f0a4SBarry Smith     } else {
2355dc0f0a4SBarry Smith       /* if no content length than must leave because you don't know if you can read again */
2365dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2375dc0f0a4SBarry Smith     }
2385dc0f0a4SBarry Smith   } while (!foundbody);
2399566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTPS result follows: \n%s\n", buff));
240b967cddfSBarry Smith 
241b967cddfSBarry Smith   SSL_free(ssl);
2429566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
2433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
244b967cddfSBarry Smith }
245b967cddfSBarry Smith 
2464683183fSBarry Smith /*@C
24704102261SBarry Smith      PetscHTTPRequest - Send a request to an HTTP server
24804102261SBarry Smith 
24904102261SBarry Smith    Input Parameters:
25004102261SBarry Smith +   type - either "POST" or "GET"
25104102261SBarry Smith .   url -  URL of request host/path
25204102261SBarry Smith .   header - additional header information, may be NULL
25304102261SBarry Smith .   ctype - data type of body, for example application/json
25404102261SBarry Smith .   body - data to send to server
255811af0c4SBarry Smith .   sock - obtained with `PetscOpenSocket()`
25604102261SBarry Smith -   buffsize - size of buffer
25704102261SBarry Smith 
25804102261SBarry Smith    Output Parameter:
25904102261SBarry Smith .   buff - everything returned from server
2604683183fSBarry Smith 
2614683183fSBarry Smith     Level: advanced
2624683183fSBarry Smith 
263db781477SPatrick Sanan .seealso: `PetscHTTPSRequest()`, `PetscOpenSocket()`, `PetscHTTPSConnect()`, `PetscPullJSONValue()`
2644683183fSBarry Smith @*/
265d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHTTPRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], int sock, char buff[], size_t buffsize)
266d71ae5a4SJacob Faibussowitsch {
26704102261SBarry Smith   char  *request;
26804102261SBarry Smith   size_t request_len;
26904102261SBarry Smith 
27004102261SBarry Smith   PetscFunctionBegin;
2719566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type, url, header, ctype, body, &request));
2729566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
27304102261SBarry Smith 
2749566063dSJacob Faibussowitsch   PetscCall(PetscBinaryWrite(sock, request, request_len, PETSC_CHAR));
2759566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
2760298d37cSMatthew G. Knepley   PetscCall(PetscBinaryRead(sock, buff, buffsize, NULL, PETSC_CHAR));
27704102261SBarry Smith   buff[buffsize - 1] = 0;
2789566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTP result follows: \n%s\n", buff));
2793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28004102261SBarry Smith }
28104102261SBarry Smith 
2824683183fSBarry Smith /*@C
2834683183fSBarry Smith       PetscHTTPSConnect - connect to a HTTPS server
2844683183fSBarry Smith 
2854683183fSBarry Smith     Input Parameters:
2864683183fSBarry Smith +    host - the name of the machine hosting the HTTPS server
2874683183fSBarry Smith .    port - the port number where the server is hosting, usually 443
288811af0c4SBarry Smith -    ctx - value obtained with `PetscSSLInitializeContext()`
2894683183fSBarry Smith 
2904683183fSBarry Smith     Output Parameters:
2914683183fSBarry Smith +    sock - socket to connect
292811af0c4SBarry Smith -    ssl - the argument passed to `PetscHTTPSRequest()`
2934683183fSBarry Smith 
2944683183fSBarry Smith     Level: advanced
2954683183fSBarry Smith 
296db781477SPatrick Sanan .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`
2974683183fSBarry Smith @*/
298d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHTTPSConnect(const char host[], int port, SSL_CTX *ctx, int *sock, SSL **ssl)
299d71ae5a4SJacob Faibussowitsch {
300b967cddfSBarry Smith   BIO *sbio;
301b967cddfSBarry Smith 
302b967cddfSBarry Smith   PetscFunctionBegin;
303b967cddfSBarry Smith   /* Connect the TCP socket*/
3049566063dSJacob Faibussowitsch   PetscCall(PetscOpenSocket(host, port, sock));
305b967cddfSBarry Smith 
306b967cddfSBarry Smith   /* Connect the SSL socket */
307b967cddfSBarry Smith   *ssl = SSL_new(ctx);
308b967cddfSBarry Smith   sbio = BIO_new_socket(*sock, BIO_NOCLOSE);
309b967cddfSBarry Smith   SSL_set_bio(*ssl, sbio, sbio);
31008401ef6SPierre Jolivet   PetscCheck(SSL_connect(*ssl) > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL connect error");
3113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
312b967cddfSBarry Smith }
313b967cddfSBarry Smith 
3144683183fSBarry Smith /*@C
3154683183fSBarry Smith      PetscPullJSONValue - Given a JSON response containing the substring with "key" : "value"  where there may or not be spaces around the : returns the value.
3164683183fSBarry Smith 
3174683183fSBarry Smith     Input Parameters:
3184683183fSBarry Smith +    buff - the char array containing the possible values
3194683183fSBarry Smith .    key - the key of the requested value
3204683183fSBarry Smith -    valuelen - the length of the array to contain the value associated with the key
3214683183fSBarry Smith 
3224683183fSBarry Smith     Output Parameters:
3234683183fSBarry Smith +    value - the value obtained
3244683183fSBarry Smith -    found - flag indicating if the value was found in the buff
3254683183fSBarry Smith 
3264683183fSBarry Smith     Level: advanced
3274683183fSBarry Smith 
328811af0c4SBarry Smith .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`, `PetscPushJSONValue()`
3294683183fSBarry Smith @*/
330d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPullJSONValue(const char buff[], const char key[], char value[], size_t valuelen, PetscBool *found)
331d71ae5a4SJacob Faibussowitsch {
33268e69593SBarry Smith   char  *v, *w;
33368e69593SBarry Smith   char   work[256];
33468e69593SBarry Smith   size_t len;
33568e69593SBarry Smith 
33668e69593SBarry Smith   PetscFunctionBegin;
337c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(work, "\"", sizeof(work)));
3389566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(work, key, sizeof(work)));
339c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(work, "\":", sizeof(work)));
3409566063dSJacob Faibussowitsch   PetscCall(PetscStrstr(buff, work, &v));
3419566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(work, &len));
34268e69593SBarry Smith   if (v) {
34368e69593SBarry Smith     v += len;
34468e69593SBarry Smith   } else {
34568e69593SBarry Smith     work[len++ - 1] = 0;
346c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(work, " :", sizeof(work)));
3479566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, work, &v));
34868e69593SBarry Smith     if (!v) {
34968e69593SBarry Smith       *found = PETSC_FALSE;
3503ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
35168e69593SBarry Smith     }
35268e69593SBarry Smith     v += len;
35368e69593SBarry Smith   }
3549566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v, '\"', &v));
35568e69593SBarry Smith   if (!v) {
35668e69593SBarry Smith     *found = PETSC_FALSE;
3573ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
35868e69593SBarry Smith   }
3599566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v + 1, '\"', &w));
36068e69593SBarry Smith   if (!w) {
36168e69593SBarry Smith     *found = PETSC_FALSE;
3623ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
36368e69593SBarry Smith   }
36468e69593SBarry Smith   *found = PETSC_TRUE;
3659566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(value, v + 1, PetscMin((size_t)(w - v), valuelen)));
3663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36768e69593SBarry Smith }
3685dc0f0a4SBarry Smith 
3695dc0f0a4SBarry Smith #include <ctype.h>
3705dc0f0a4SBarry Smith 
3714683183fSBarry Smith /*@C
3724683183fSBarry Smith     PetscPushJSONValue -  Puts a "key" : "value" pair onto a string
3735dc0f0a4SBarry Smith 
3744683183fSBarry Smith     Input Parameters:
3754683183fSBarry Smith +   buffer - the char array where the value will be put
3764683183fSBarry Smith .   key - the key value to be set
3774683183fSBarry Smith .   value - the value associated with the key
3784683183fSBarry Smith -   bufflen - the size of the buffer (currently ignored)
3794683183fSBarry Smith 
3804683183fSBarry Smith     Level: advanced
3814683183fSBarry Smith 
382811af0c4SBarry Smith     Note:
38395452b02SPatrick Sanan     Ignores lengths so can cause buffer overflow
384811af0c4SBarry Smith 
385811af0c4SBarry Smith .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`, `PetscPullJSONValue()`
3864683183fSBarry Smith @*/
387d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPushJSONValue(char buff[], const char key[], const char value[], size_t bufflen)
388d71ae5a4SJacob Faibussowitsch {
3895dc0f0a4SBarry Smith   size_t    len;
3905dc0f0a4SBarry Smith   PetscBool special;
3915dc0f0a4SBarry Smith 
3925dc0f0a4SBarry Smith   PetscFunctionBegin;
3939566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(value, "null", &special));
39448a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcmp(value, "true", &special));
39548a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcmp(value, "false", &special));
3965dc0f0a4SBarry Smith   if (!special) {
3975dc0f0a4SBarry Smith     PetscInt i;
3985dc0f0a4SBarry Smith 
3999566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(value, &len));
4005dc0f0a4SBarry Smith     special = PETSC_TRUE;
4015dc0f0a4SBarry Smith     for (i = 0; i < (int)len; i++) {
4025dc0f0a4SBarry Smith       if (!isdigit(value[i])) {
4035dc0f0a4SBarry Smith         special = PETSC_FALSE;
4045dc0f0a4SBarry Smith         break;
4055dc0f0a4SBarry Smith       }
4065dc0f0a4SBarry Smith     }
4075dc0f0a4SBarry Smith   }
4085dc0f0a4SBarry Smith 
409c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, "\"", bufflen));
410c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, key, bufflen));
411c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, "\":", bufflen));
412c6a7a370SJeremy L Thompson   if (!special) PetscCall(PetscStrlcat(buff, "\"", bufflen));
413c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, value, bufflen));
414c6a7a370SJeremy L Thompson   if (!special) PetscCall(PetscStrlcat(buff, "\"", bufflen));
4153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4165dc0f0a4SBarry Smith }
417