xref: /petsc/src/sys/webclient/client.c (revision 1c7e414e2723e48d2171f9bad7df83055ad45d0b)
1b967cddfSBarry Smith 
20efc6a03SBarry Smith #include <petscwebclient.h>
3*1c7e414eSJacob 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
2968e69593SBarry Smith $    saws/CA.pl  -newcert  (using the passphrase of password)
30b967cddfSBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
31b967cddfSBarry Smith 
32b967cddfSBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
33b967cddfSBarry Smith     silly but it was all I could figure out.
34b967cddfSBarry Smith 
35db781477SPatrick Sanan .seealso: `PetscSSLDestroyContext()`, `PetscHTTPSConnect()`, `PetscHTTPSRequest()`
364683183fSBarry Smith @*/
37d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
38d71ae5a4SJacob Faibussowitsch {
39b967cddfSBarry Smith   SSL_CTX *ctx;
404a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
41b967cddfSBarry Smith   char      keyfile[PETSC_MAX_PATH_LEN];
42b967cddfSBarry Smith   PetscBool exists;
43b967cddfSBarry Smith #endif
44b967cddfSBarry Smith 
45b967cddfSBarry Smith   PetscFunctionBegin;
46b967cddfSBarry Smith   if (!bio_err) {
47b967cddfSBarry Smith     SSL_library_init();
48b967cddfSBarry Smith     SSL_load_error_strings();
49b967cddfSBarry Smith     bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
50b967cddfSBarry Smith   }
51b967cddfSBarry Smith 
52b967cddfSBarry Smith   /* Set up a SIGPIPE handler */
53b967cddfSBarry Smith   signal(SIGPIPE, sigpipe_handle);
54b967cddfSBarry Smith 
55ecd1d7b8SBarry Smith /* suggested at https://mta.openssl.org/pipermail/openssl-dev/2015-May/001449.html */
56ecd1d7b8SBarry Smith #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
57ecd1d7b8SBarry Smith   ctx = SSL_CTX_new(TLS_client_method());
58ecd1d7b8SBarry Smith #else
59ecd1d7b8SBarry Smith   ctx = SSL_CTX_new(SSLv23_client_method());
60ecd1d7b8SBarry Smith #endif
615dc0f0a4SBarry Smith   SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
62b967cddfSBarry Smith 
634a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
64b967cddfSBarry Smith   /* Locate keyfile */
65c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(keyfile, "sslclient.pem", sizeof(keyfile)));
669566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(keyfile, 'r', &exists));
67b967cddfSBarry Smith   if (!exists) {
689566063dSJacob Faibussowitsch     PetscCall(PetscGetHomeDirectory(keyfile, PETSC_MAX_PATH_LEN));
69c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "/", sizeof(keyfile)));
70c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "sslclient.pem", sizeof(keyfile)));
719566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(keyfile, 'r', &exists));
7228b400f6SJacob Faibussowitsch     PetscCheck(exists, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate sslclient.pem file in current directory or home directory");
73b967cddfSBarry Smith   }
74b967cddfSBarry Smith 
75b967cddfSBarry Smith   /* Load our keys and certificates*/
76cc73adaaSBarry Smith   PetscCheck(SSL_CTX_use_certificate_chain_file(ctx, keyfile), PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot read certificate file");
77b967cddfSBarry Smith 
78b967cddfSBarry Smith   SSL_CTX_set_default_passwd_cb(ctx, password_cb);
79cc73adaaSBarry Smith   PetscCheck(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM), PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot read key file");
80b967cddfSBarry Smith #endif
81b967cddfSBarry Smith 
82b967cddfSBarry Smith   *octx = ctx;
833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
84b967cddfSBarry Smith }
85b967cddfSBarry Smith 
864683183fSBarry Smith /*@C
87811af0c4SBarry Smith      PetscSSLDestroyContext - frees a `SSL_CTX` obtained with `PetscSSLInitializeContext()`
884683183fSBarry Smith 
894683183fSBarry Smith      Input Parameter:
90811af0c4SBarry Smith .     ctx - the `SSL_CTX`
914683183fSBarry Smith 
924683183fSBarry Smith     Level: advanced
934683183fSBarry Smith 
94db781477SPatrick Sanan .seealso: `PetscSSLInitializeContext()`, `PetscHTTPSConnect()`
954683183fSBarry Smith @*/
96d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
97d71ae5a4SJacob Faibussowitsch {
98b967cddfSBarry Smith   PetscFunctionBegin;
99b967cddfSBarry Smith   SSL_CTX_free(ctx);
1003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
101b967cddfSBarry Smith }
102b967cddfSBarry Smith 
103d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscHTTPBuildRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], char **outrequest)
104d71ae5a4SJacob Faibussowitsch {
105b967cddfSBarry Smith   char     *request = 0;
10693e1d32fSBarry Smith   char      contentlength[40], contenttype[80], *path, *host;
1077a3410edSBarry Smith   size_t    request_len, headlen, bodylen, contentlen, pathlen, hostlen, typelen, contenttypelen = 0;
108b967cddfSBarry Smith   PetscBool flg;
109b967cddfSBarry Smith 
110b967cddfSBarry Smith   PetscFunctionBegin;
1119566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(url, &host));
1129566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(host, '/', &path));
11328b400f6SJacob Faibussowitsch   PetscCheck(path, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "url must contain / it is %s", url);
114c245270aSBarry Smith   *path = 0;
1159566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(host, &hostlen));
11693e1d32fSBarry Smith 
1179566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(url, '/', &path));
1189566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(path, &pathlen));
11993e1d32fSBarry Smith 
120b967cddfSBarry Smith   if (header) {
1219566063dSJacob Faibussowitsch     PetscCall(PetscStrendswith(header, "\r\n", &flg));
122d8174014SToby Isaac     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "header must end with \\r\\n");
123b967cddfSBarry Smith   }
124b967cddfSBarry Smith 
1259566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(type, &typelen));
126b967cddfSBarry Smith   if (ctype) {
1279566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(contenttype, 80, "Content-Type: %s\r\n", ctype));
1289566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(contenttype, &contenttypelen));
129b967cddfSBarry Smith   }
1309566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(header, &headlen));
1319566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(body, &bodylen));
1329566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(contentlength, 40, "Content-Length: %d\r\n\r\n", (int)bodylen));
1339566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(contentlength, &contentlen));
134b967cddfSBarry Smith 
135b967cddfSBarry Smith   /* Now construct our HTTP request */
13693e1d32fSBarry Smith   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
1379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(request_len, &request));
138c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(request, type, request_len));
139c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, " ", request_len));
140c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, path, request_len));
141c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, " HTTP/1.1\r\nHost: ", request_len));
142c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, host, request_len));
1439566063dSJacob Faibussowitsch   PetscCall(PetscFree(host));
144c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, "\r\nUser-Agent:PETScClient\r\n", request_len));
145c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, header, request_len));
146c6a7a370SJeremy L Thompson   if (ctype) PetscCall(PetscStrlcat(request, contenttype, request_len));
147c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, contentlength, request_len));
148c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, body, request_len));
1499566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
1509566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTPS request follows: \n%s\n", request));
151b967cddfSBarry Smith 
15204102261SBarry Smith   *outrequest = request;
1533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15404102261SBarry Smith }
15504102261SBarry Smith 
1564683183fSBarry Smith /*@C
15704102261SBarry Smith      PetscHTTPSRequest - Send a request to an HTTPS server
15804102261SBarry Smith 
15904102261SBarry Smith    Input Parameters:
16004102261SBarry Smith +   type - either "POST" or "GET"
16104102261SBarry Smith .   url -  URL of request host/path
16204102261SBarry Smith .   header - additional header information, may be NULL
16304102261SBarry Smith .   ctype - data type of body, for example application/json
16404102261SBarry Smith .   body - data to send to server
165811af0c4SBarry Smith .   ssl - obtained with `PetscHTTPSConnect()`
16604102261SBarry Smith -   buffsize - size of buffer
16704102261SBarry Smith 
16804102261SBarry Smith    Output Parameter:
16904102261SBarry Smith .   buff - everything returned from server
1704683183fSBarry Smith 
1714683183fSBarry Smith     Level: advanced
1724683183fSBarry Smith 
173db781477SPatrick Sanan .seealso: `PetscHTTPRequest()`, `PetscHTTPSConnect()`, `PetscSSLInitializeContext()`, `PetscSSLDestroyContext()`, `PetscPullJSONValue()`
1744683183fSBarry Smith @*/
175d71ae5a4SJacob 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)
176d71ae5a4SJacob Faibussowitsch {
17704102261SBarry Smith   char     *request;
17804102261SBarry Smith   int       r;
17904102261SBarry Smith   size_t    request_len, len;
1805dc0f0a4SBarry Smith   PetscBool foundbody = PETSC_FALSE;
18104102261SBarry Smith 
18204102261SBarry Smith   PetscFunctionBegin;
1839566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type, url, header, ctype, body, &request));
1849566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
18504102261SBarry Smith 
186d8dcb26dSBarry Smith   r = SSL_write(ssl, request, (int)request_len);
187b967cddfSBarry Smith   switch (SSL_get_error(ssl, r)) {
188d71ae5a4SJacob Faibussowitsch   case SSL_ERROR_NONE:
189d71ae5a4SJacob Faibussowitsch     PetscCheck(request_len == (size_t)r, PETSC_COMM_SELF, PETSC_ERR_LIB, "Incomplete write to SSL socket");
190d71ae5a4SJacob Faibussowitsch     break;
191d71ae5a4SJacob Faibussowitsch   default:
192d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL socket write problem");
193b967cddfSBarry Smith   }
194b967cddfSBarry Smith 
1955dc0f0a4SBarry Smith   /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
1969566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(buff, buffsize));
1975dc0f0a4SBarry Smith   len       = 0;
1985dc0f0a4SBarry Smith   foundbody = PETSC_FALSE;
1995dc0f0a4SBarry Smith   do {
2005dc0f0a4SBarry Smith     char  *clen;
2015dc0f0a4SBarry Smith     int    cl;
2025dc0f0a4SBarry Smith     size_t nlen;
2035dc0f0a4SBarry Smith 
2045dc0f0a4SBarry Smith     r = SSL_read(ssl, buff + len, (int)buffsize);
2055dc0f0a4SBarry Smith     len += r;
206b967cddfSBarry Smith     switch (SSL_get_error(ssl, r)) {
207d71ae5a4SJacob Faibussowitsch     case SSL_ERROR_NONE:
208d71ae5a4SJacob Faibussowitsch       break;
209b967cddfSBarry Smith     case SSL_ERROR_ZERO_RETURN:
2105dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2115dc0f0a4SBarry Smith       SSL_shutdown(ssl);
212b967cddfSBarry Smith       break;
213d71ae5a4SJacob Faibussowitsch     case SSL_ERROR_SYSCALL:
214d71ae5a4SJacob Faibussowitsch       foundbody = PETSC_TRUE;
215d71ae5a4SJacob Faibussowitsch       break;
216d71ae5a4SJacob Faibussowitsch     default:
217d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL read problem");
218b967cddfSBarry Smith     }
2195dc0f0a4SBarry Smith 
2209566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, "Content-Length: ", &clen));
2215dc0f0a4SBarry Smith     if (clen) {
2225dc0f0a4SBarry Smith       clen += 15;
2235dc0f0a4SBarry Smith       sscanf(clen, "%d", &cl);
2245dc0f0a4SBarry Smith       if (!cl) foundbody = PETSC_TRUE;
2255dc0f0a4SBarry Smith       else {
2269566063dSJacob Faibussowitsch         PetscCall(PetscStrstr(buff, "\r\n\r\n", &clen));
2275dc0f0a4SBarry Smith         if (clen) {
2289566063dSJacob Faibussowitsch           PetscCall(PetscStrlen(clen, &nlen));
2295dc0f0a4SBarry Smith           if (nlen - 4 == (size_t)cl) foundbody = PETSC_TRUE;
2305dc0f0a4SBarry Smith         }
2315dc0f0a4SBarry Smith       }
2325dc0f0a4SBarry Smith     } else {
2335dc0f0a4SBarry Smith       /* if no content length than must leave because you don't know if you can read again */
2345dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2355dc0f0a4SBarry Smith     }
2365dc0f0a4SBarry Smith   } while (!foundbody);
2379566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTPS result follows: \n%s\n", buff));
238b967cddfSBarry Smith 
239b967cddfSBarry Smith   SSL_free(ssl);
2409566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
2413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
242b967cddfSBarry Smith }
243b967cddfSBarry Smith 
2444683183fSBarry Smith /*@C
24504102261SBarry Smith      PetscHTTPRequest - Send a request to an HTTP server
24604102261SBarry Smith 
24704102261SBarry Smith    Input Parameters:
24804102261SBarry Smith +   type - either "POST" or "GET"
24904102261SBarry Smith .   url -  URL of request host/path
25004102261SBarry Smith .   header - additional header information, may be NULL
25104102261SBarry Smith .   ctype - data type of body, for example application/json
25204102261SBarry Smith .   body - data to send to server
253811af0c4SBarry Smith .   sock - obtained with `PetscOpenSocket()`
25404102261SBarry Smith -   buffsize - size of buffer
25504102261SBarry Smith 
25604102261SBarry Smith    Output Parameter:
25704102261SBarry Smith .   buff - everything returned from server
2584683183fSBarry Smith 
2594683183fSBarry Smith     Level: advanced
2604683183fSBarry Smith 
261db781477SPatrick Sanan .seealso: `PetscHTTPSRequest()`, `PetscOpenSocket()`, `PetscHTTPSConnect()`, `PetscPullJSONValue()`
2624683183fSBarry Smith @*/
263d71ae5a4SJacob 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)
264d71ae5a4SJacob Faibussowitsch {
26504102261SBarry Smith   char  *request;
26604102261SBarry Smith   size_t request_len;
26704102261SBarry Smith 
26804102261SBarry Smith   PetscFunctionBegin;
2699566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type, url, header, ctype, body, &request));
2709566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
27104102261SBarry Smith 
2729566063dSJacob Faibussowitsch   PetscCall(PetscBinaryWrite(sock, request, request_len, PETSC_CHAR));
2739566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
2740298d37cSMatthew G. Knepley   PetscCall(PetscBinaryRead(sock, buff, buffsize, NULL, PETSC_CHAR));
27504102261SBarry Smith   buff[buffsize - 1] = 0;
2769566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTP result follows: \n%s\n", buff));
2773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27804102261SBarry Smith }
27904102261SBarry Smith 
2804683183fSBarry Smith /*@C
2814683183fSBarry Smith       PetscHTTPSConnect - connect to a HTTPS server
2824683183fSBarry Smith 
2834683183fSBarry Smith     Input Parameters:
2844683183fSBarry Smith +    host - the name of the machine hosting the HTTPS server
2854683183fSBarry Smith .    port - the port number where the server is hosting, usually 443
286811af0c4SBarry Smith -    ctx - value obtained with `PetscSSLInitializeContext()`
2874683183fSBarry Smith 
2884683183fSBarry Smith     Output Parameters:
2894683183fSBarry Smith +    sock - socket to connect
290811af0c4SBarry Smith -    ssl - the argument passed to `PetscHTTPSRequest()`
2914683183fSBarry Smith 
2924683183fSBarry Smith     Level: advanced
2934683183fSBarry Smith 
294db781477SPatrick Sanan .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`
2954683183fSBarry Smith @*/
296d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHTTPSConnect(const char host[], int port, SSL_CTX *ctx, int *sock, SSL **ssl)
297d71ae5a4SJacob Faibussowitsch {
298b967cddfSBarry Smith   BIO *sbio;
299b967cddfSBarry Smith 
300b967cddfSBarry Smith   PetscFunctionBegin;
301b967cddfSBarry Smith   /* Connect the TCP socket*/
3029566063dSJacob Faibussowitsch   PetscCall(PetscOpenSocket(host, port, sock));
303b967cddfSBarry Smith 
304b967cddfSBarry Smith   /* Connect the SSL socket */
305b967cddfSBarry Smith   *ssl = SSL_new(ctx);
306b967cddfSBarry Smith   sbio = BIO_new_socket(*sock, BIO_NOCLOSE);
307b967cddfSBarry Smith   SSL_set_bio(*ssl, sbio, sbio);
30808401ef6SPierre Jolivet   PetscCheck(SSL_connect(*ssl) > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL connect error");
3093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
310b967cddfSBarry Smith }
311b967cddfSBarry Smith 
3124683183fSBarry Smith /*@C
3134683183fSBarry Smith      PetscPullJSONValue - Given a JSON response containing the substring with "key" : "value"  where there may or not be spaces around the : returns the value.
3144683183fSBarry Smith 
3154683183fSBarry Smith     Input Parameters:
3164683183fSBarry Smith +    buff - the char array containing the possible values
3174683183fSBarry Smith .    key - the key of the requested value
3184683183fSBarry Smith -    valuelen - the length of the array to contain the value associated with the key
3194683183fSBarry Smith 
3204683183fSBarry Smith     Output Parameters:
3214683183fSBarry Smith +    value - the value obtained
3224683183fSBarry Smith -    found - flag indicating if the value was found in the buff
3234683183fSBarry Smith 
3244683183fSBarry Smith     Level: advanced
3254683183fSBarry Smith 
326811af0c4SBarry Smith .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`, `PetscPushJSONValue()`
3274683183fSBarry Smith @*/
328d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPullJSONValue(const char buff[], const char key[], char value[], size_t valuelen, PetscBool *found)
329d71ae5a4SJacob Faibussowitsch {
33068e69593SBarry Smith   char  *v, *w;
33168e69593SBarry Smith   char   work[256];
33268e69593SBarry Smith   size_t len;
33368e69593SBarry Smith 
33468e69593SBarry Smith   PetscFunctionBegin;
335c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(work, "\"", sizeof(work)));
3369566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(work, key, sizeof(work)));
337c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(work, "\":", sizeof(work)));
3389566063dSJacob Faibussowitsch   PetscCall(PetscStrstr(buff, work, &v));
3399566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(work, &len));
34068e69593SBarry Smith   if (v) {
34168e69593SBarry Smith     v += len;
34268e69593SBarry Smith   } else {
34368e69593SBarry Smith     work[len++ - 1] = 0;
344c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(work, " :", sizeof(work)));
3459566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, work, &v));
34668e69593SBarry Smith     if (!v) {
34768e69593SBarry Smith       *found = PETSC_FALSE;
3483ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
34968e69593SBarry Smith     }
35068e69593SBarry Smith     v += len;
35168e69593SBarry Smith   }
3529566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v, '\"', &v));
35368e69593SBarry Smith   if (!v) {
35468e69593SBarry Smith     *found = PETSC_FALSE;
3553ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
35668e69593SBarry Smith   }
3579566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v + 1, '\"', &w));
35868e69593SBarry Smith   if (!w) {
35968e69593SBarry Smith     *found = PETSC_FALSE;
3603ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
36168e69593SBarry Smith   }
36268e69593SBarry Smith   *found = PETSC_TRUE;
3639566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(value, v + 1, PetscMin((size_t)(w - v), valuelen)));
3643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36568e69593SBarry Smith }
3665dc0f0a4SBarry Smith 
3675dc0f0a4SBarry Smith #include <ctype.h>
3685dc0f0a4SBarry Smith 
3694683183fSBarry Smith /*@C
3704683183fSBarry Smith     PetscPushJSONValue -  Puts a "key" : "value" pair onto a string
3715dc0f0a4SBarry Smith 
3724683183fSBarry Smith     Input Parameters:
3734683183fSBarry Smith +   buffer - the char array where the value will be put
3744683183fSBarry Smith .   key - the key value to be set
3754683183fSBarry Smith .   value - the value associated with the key
3764683183fSBarry Smith -   bufflen - the size of the buffer (currently ignored)
3774683183fSBarry Smith 
3784683183fSBarry Smith     Level: advanced
3794683183fSBarry Smith 
380811af0c4SBarry Smith     Note:
38195452b02SPatrick Sanan     Ignores lengths so can cause buffer overflow
382811af0c4SBarry Smith 
383811af0c4SBarry Smith .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`, `PetscPullJSONValue()`
3844683183fSBarry Smith @*/
385d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPushJSONValue(char buff[], const char key[], const char value[], size_t bufflen)
386d71ae5a4SJacob Faibussowitsch {
3875dc0f0a4SBarry Smith   size_t    len;
3885dc0f0a4SBarry Smith   PetscBool special;
3895dc0f0a4SBarry Smith 
3905dc0f0a4SBarry Smith   PetscFunctionBegin;
3919566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(value, "null", &special));
39248a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcmp(value, "true", &special));
39348a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcmp(value, "false", &special));
3945dc0f0a4SBarry Smith   if (!special) {
3955dc0f0a4SBarry Smith     PetscInt i;
3965dc0f0a4SBarry Smith 
3979566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(value, &len));
3985dc0f0a4SBarry Smith     special = PETSC_TRUE;
3995dc0f0a4SBarry Smith     for (i = 0; i < (int)len; i++) {
4005dc0f0a4SBarry Smith       if (!isdigit(value[i])) {
4015dc0f0a4SBarry Smith         special = PETSC_FALSE;
4025dc0f0a4SBarry Smith         break;
4035dc0f0a4SBarry Smith       }
4045dc0f0a4SBarry Smith     }
4055dc0f0a4SBarry Smith   }
4065dc0f0a4SBarry Smith 
407c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, "\"", bufflen));
408c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, key, bufflen));
409c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, "\":", bufflen));
410c6a7a370SJeremy L Thompson   if (!special) PetscCall(PetscStrlcat(buff, "\"", bufflen));
411c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, value, bufflen));
412c6a7a370SJeremy L Thompson   if (!special) PetscCall(PetscStrlcat(buff, "\"", bufflen));
4133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4145dc0f0a4SBarry Smith }
415