xref: /petsc/src/sys/webclient/client.c (revision 373304a1fd22002640631235ee36a21c261ab6d4)
10efc6a03SBarry Smith #include <petscwebclient.h>
21c7e414eSJacob Faibussowitsch PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wdeprecated-declarations")
3b967cddfSBarry Smith 
4b967cddfSBarry Smith static BIO *bio_err = NULL;
5b967cddfSBarry Smith 
6b967cddfSBarry Smith #define PASSWORD "password"
7b967cddfSBarry Smith 
84a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
password_cb(char * buf,int num,int rwflag,void * userdata)9d71ae5a4SJacob Faibussowitsch static int password_cb(char *buf, int num, int rwflag, void *userdata)
10d71ae5a4SJacob Faibussowitsch {
114ad8454bSPierre Jolivet   if (num < strlen(PASSWORD) + 1) return 0;
12b967cddfSBarry Smith   strcpy(buf, PASSWORD);
134ad8454bSPierre Jolivet   return strlen(PASSWORD);
14b967cddfSBarry Smith }
15b967cddfSBarry Smith #endif
16b967cddfSBarry Smith 
sigpipe_handle(int x)179371c9d4SSatish Balay static void sigpipe_handle(int x) { }
18b967cddfSBarry Smith 
194683183fSBarry Smith /*@C
20b967cddfSBarry Smith   PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
21b967cddfSBarry Smith 
224683183fSBarry Smith   Output Parameter:
23811af0c4SBarry Smith . octx - the SSL_CTX to be passed to `PetscHTTPSConnect90`
24b967cddfSBarry Smith 
254683183fSBarry Smith   Level: advanced
264683183fSBarry Smith 
274683183fSBarry Smith     If PETSc was ./configure -with-ssl-certificate requires the user have created a self-signed certificate with
2837fdd005SBarry Smith .vb
2937fdd005SBarry Smith     saws/CA.pl  -newcert  (using the passphrase of password)
3037fdd005SBarry Smith     cat newkey.pem newcert.pem > sslclient.pem
3137fdd005SBarry Smith .ve
32b967cddfSBarry Smith 
33b967cddfSBarry Smith   and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
34b967cddfSBarry Smith   silly but it was all I could figure out.
35b967cddfSBarry Smith 
36db781477SPatrick Sanan .seealso: `PetscSSLDestroyContext()`, `PetscHTTPSConnect()`, `PetscHTTPSRequest()`
374683183fSBarry Smith @*/
PetscSSLInitializeContext(SSL_CTX ** octx)38d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
39d71ae5a4SJacob Faibussowitsch {
40b967cddfSBarry Smith   SSL_CTX *ctx;
414a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
42b967cddfSBarry Smith   char      keyfile[PETSC_MAX_PATH_LEN];
43b967cddfSBarry Smith   PetscBool exists;
44b967cddfSBarry Smith #endif
45b967cddfSBarry Smith 
46b967cddfSBarry Smith   PetscFunctionBegin;
47b967cddfSBarry Smith   if (!bio_err) {
48b967cddfSBarry Smith     SSL_library_init();
49b967cddfSBarry Smith     SSL_load_error_strings();
50b967cddfSBarry Smith     bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
51b967cddfSBarry Smith   }
52b967cddfSBarry Smith 
53b967cddfSBarry Smith   /* Set up a SIGPIPE handler */
54b967cddfSBarry Smith   signal(SIGPIPE, sigpipe_handle);
55b967cddfSBarry Smith 
56ecd1d7b8SBarry Smith /* suggested at https://mta.openssl.org/pipermail/openssl-dev/2015-May/001449.html */
57ecd1d7b8SBarry Smith #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
58ecd1d7b8SBarry Smith   ctx = SSL_CTX_new(TLS_client_method());
59ecd1d7b8SBarry Smith #else
60ecd1d7b8SBarry Smith   ctx = SSL_CTX_new(SSLv23_client_method());
61ecd1d7b8SBarry Smith #endif
625dc0f0a4SBarry Smith   SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
63b967cddfSBarry Smith 
644a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
65b967cddfSBarry Smith   /* Locate keyfile */
66c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(keyfile, "sslclient.pem", sizeof(keyfile)));
679566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(keyfile, 'r', &exists));
68b967cddfSBarry Smith   if (!exists) {
699566063dSJacob Faibussowitsch     PetscCall(PetscGetHomeDirectory(keyfile, PETSC_MAX_PATH_LEN));
70c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "/", sizeof(keyfile)));
71c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(keyfile, "sslclient.pem", sizeof(keyfile)));
729566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(keyfile, 'r', &exists));
7328b400f6SJacob Faibussowitsch     PetscCheck(exists, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate sslclient.pem file in current directory or home directory");
74b967cddfSBarry Smith   }
75b967cddfSBarry Smith 
76b967cddfSBarry Smith   /* Load our keys and certificates*/
77cc73adaaSBarry Smith   PetscCheck(SSL_CTX_use_certificate_chain_file(ctx, keyfile), PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot read certificate file");
78b967cddfSBarry Smith 
79b967cddfSBarry Smith   SSL_CTX_set_default_passwd_cb(ctx, password_cb);
80cc73adaaSBarry Smith   PetscCheck(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM), PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot read key file");
81b967cddfSBarry Smith #endif
82b967cddfSBarry Smith 
83b967cddfSBarry Smith   *octx = ctx;
843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
85b967cddfSBarry Smith }
86b967cddfSBarry Smith 
874683183fSBarry Smith /*@C
88811af0c4SBarry Smith   PetscSSLDestroyContext - frees a `SSL_CTX` obtained with `PetscSSLInitializeContext()`
894683183fSBarry Smith 
904683183fSBarry Smith   Input Parameter:
91811af0c4SBarry Smith . ctx - the `SSL_CTX`
924683183fSBarry Smith 
934683183fSBarry Smith   Level: advanced
944683183fSBarry Smith 
95db781477SPatrick Sanan .seealso: `PetscSSLInitializeContext()`, `PetscHTTPSConnect()`
964683183fSBarry Smith @*/
PetscSSLDestroyContext(SSL_CTX * ctx)97d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
98d71ae5a4SJacob Faibussowitsch {
99b967cddfSBarry Smith   PetscFunctionBegin;
100b967cddfSBarry Smith   SSL_CTX_free(ctx);
1013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102b967cddfSBarry Smith }
103b967cddfSBarry Smith 
PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char ** outrequest)104d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscHTTPBuildRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], char **outrequest)
105d71ae5a4SJacob Faibussowitsch {
106b967cddfSBarry Smith   char     *request = 0;
10793e1d32fSBarry Smith   char      contentlength[40], contenttype[80], *path, *host;
1087a3410edSBarry Smith   size_t    request_len, headlen, bodylen, contentlen, pathlen, hostlen, typelen, contenttypelen = 0;
109b967cddfSBarry Smith   PetscBool flg;
110b967cddfSBarry Smith 
111b967cddfSBarry Smith   PetscFunctionBegin;
1129566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(url, &host));
1139566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(host, '/', &path));
11400045ab3SPierre Jolivet   PetscCheck(path, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "URL must contain /, it is %s", url);
115c245270aSBarry Smith   *path = 0;
1169566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(host, &hostlen));
11793e1d32fSBarry Smith 
1189566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(url, '/', &path));
1199566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(path, &pathlen));
12093e1d32fSBarry Smith 
121b967cddfSBarry Smith   if (header) {
1229566063dSJacob Faibussowitsch     PetscCall(PetscStrendswith(header, "\r\n", &flg));
12300045ab3SPierre Jolivet     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Header must end with \\r\\n, it is %s", header);
124b967cddfSBarry Smith   }
125b967cddfSBarry Smith 
1269566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(type, &typelen));
127b967cddfSBarry Smith   if (ctype) {
1289566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(contenttype, 80, "Content-Type: %s\r\n", ctype));
1299566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(contenttype, &contenttypelen));
130b967cddfSBarry Smith   }
1319566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(header, &headlen));
1329566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(body, &bodylen));
1339566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(contentlength, 40, "Content-Length: %d\r\n\r\n", (int)bodylen));
1349566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(contentlength, &contentlen));
135b967cddfSBarry Smith 
136b967cddfSBarry Smith   /* Now construct our HTTP request */
13793e1d32fSBarry Smith   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
1389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(request_len, &request));
139c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(request, type, request_len));
140c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, " ", request_len));
141c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, path, request_len));
142c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, " HTTP/1.1\r\nHost: ", request_len));
143c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, host, request_len));
1449566063dSJacob Faibussowitsch   PetscCall(PetscFree(host));
145c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, "\r\nUser-Agent:PETScClient\r\n", request_len));
146c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, header, request_len));
147c6a7a370SJeremy L Thompson   if (ctype) PetscCall(PetscStrlcat(request, contenttype, request_len));
148c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, contentlength, request_len));
149c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(request, body, request_len));
1509566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
1519566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTPS request follows: \n%s\n", request));
152b967cddfSBarry Smith 
15304102261SBarry Smith   *outrequest = request;
1543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15504102261SBarry Smith }
15604102261SBarry Smith 
1574683183fSBarry Smith /*@C
15804102261SBarry Smith   PetscHTTPSRequest - Send a request to an HTTPS server
15904102261SBarry Smith 
16004102261SBarry Smith   Input Parameters:
16104102261SBarry Smith + type     - either "POST" or "GET"
16204102261SBarry Smith . url      - URL of request host/path
163*dc9a610eSPierre Jolivet . header   - additional header information, may be `NULL`
16404102261SBarry Smith . ctype    - data type of body, for example application/json
16504102261SBarry Smith . body     - data to send to server
166811af0c4SBarry Smith . ssl      - obtained with `PetscHTTPSConnect()`
16704102261SBarry Smith - buffsize - size of buffer
16804102261SBarry Smith 
16904102261SBarry Smith   Output Parameter:
17004102261SBarry Smith . buff - everything returned from server
1714683183fSBarry Smith 
1724683183fSBarry Smith   Level: advanced
1734683183fSBarry Smith 
174db781477SPatrick Sanan .seealso: `PetscHTTPRequest()`, `PetscHTTPSConnect()`, `PetscSSLInitializeContext()`, `PetscSSLDestroyContext()`, `PetscPullJSONValue()`
1754683183fSBarry Smith @*/
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 PetscErrorCode PetscHTTPSRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], SSL *ssl, char buff[], size_t buffsize)
177d71ae5a4SJacob Faibussowitsch {
17804102261SBarry Smith   char     *request;
17904102261SBarry Smith   int       r;
18004102261SBarry Smith   size_t    request_len, len;
1815dc0f0a4SBarry Smith   PetscBool foundbody = PETSC_FALSE;
18204102261SBarry Smith 
18304102261SBarry Smith   PetscFunctionBegin;
1849566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type, url, header, ctype, body, &request));
1859566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
18604102261SBarry Smith 
187d8dcb26dSBarry Smith   r = SSL_write(ssl, request, (int)request_len);
188b967cddfSBarry Smith   switch (SSL_get_error(ssl, r)) {
189d71ae5a4SJacob Faibussowitsch   case SSL_ERROR_NONE:
190d71ae5a4SJacob Faibussowitsch     PetscCheck(request_len == (size_t)r, PETSC_COMM_SELF, PETSC_ERR_LIB, "Incomplete write to SSL socket");
191d71ae5a4SJacob Faibussowitsch     break;
192d71ae5a4SJacob Faibussowitsch   default:
193d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL socket write problem");
194b967cddfSBarry Smith   }
195b967cddfSBarry Smith 
1965dc0f0a4SBarry Smith   /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
1979566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(buff, buffsize));
1985dc0f0a4SBarry Smith   len       = 0;
1995dc0f0a4SBarry Smith   foundbody = PETSC_FALSE;
2005dc0f0a4SBarry Smith   do {
2015dc0f0a4SBarry Smith     char  *clen;
2025dc0f0a4SBarry Smith     int    cl;
2035dc0f0a4SBarry Smith     size_t nlen;
2045dc0f0a4SBarry Smith 
2055dc0f0a4SBarry Smith     r = SSL_read(ssl, buff + len, (int)buffsize);
2065dc0f0a4SBarry Smith     len += r;
207b967cddfSBarry Smith     switch (SSL_get_error(ssl, r)) {
208d71ae5a4SJacob Faibussowitsch     case SSL_ERROR_NONE:
209d71ae5a4SJacob Faibussowitsch       break;
210b967cddfSBarry Smith     case SSL_ERROR_ZERO_RETURN:
2115dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2125dc0f0a4SBarry Smith       SSL_shutdown(ssl);
213b967cddfSBarry Smith       break;
214d71ae5a4SJacob Faibussowitsch     case SSL_ERROR_SYSCALL:
215d71ae5a4SJacob Faibussowitsch       foundbody = PETSC_TRUE;
216d71ae5a4SJacob Faibussowitsch       break;
217d71ae5a4SJacob Faibussowitsch     default:
218d71ae5a4SJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL read problem");
219b967cddfSBarry Smith     }
2205dc0f0a4SBarry Smith 
2219566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, "Content-Length: ", &clen));
2225dc0f0a4SBarry Smith     if (clen) {
2235dc0f0a4SBarry Smith       clen += 15;
2245dc0f0a4SBarry Smith       sscanf(clen, "%d", &cl);
2255dc0f0a4SBarry Smith       if (!cl) foundbody = PETSC_TRUE;
2265dc0f0a4SBarry Smith       else {
2279566063dSJacob Faibussowitsch         PetscCall(PetscStrstr(buff, "\r\n\r\n", &clen));
2285dc0f0a4SBarry Smith         if (clen) {
2299566063dSJacob Faibussowitsch           PetscCall(PetscStrlen(clen, &nlen));
2305dc0f0a4SBarry Smith           if (nlen - 4 == (size_t)cl) foundbody = PETSC_TRUE;
2315dc0f0a4SBarry Smith         }
2325dc0f0a4SBarry Smith       }
2335dc0f0a4SBarry Smith     } else {
2345dc0f0a4SBarry Smith       /* if no content length than must leave because you don't know if you can read again */
2355dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2365dc0f0a4SBarry Smith     }
2375dc0f0a4SBarry Smith   } while (!foundbody);
2389566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTPS result follows: \n%s\n", buff));
239b967cddfSBarry Smith 
240b967cddfSBarry Smith   SSL_free(ssl);
2419566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
2423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
243b967cddfSBarry Smith }
244b967cddfSBarry Smith 
2454683183fSBarry Smith /*@C
24604102261SBarry Smith   PetscHTTPRequest - Send a request to an HTTP server
24704102261SBarry Smith 
24804102261SBarry Smith   Input Parameters:
24904102261SBarry Smith + type     - either "POST" or "GET"
25004102261SBarry Smith . url      - URL of request host/path
251*dc9a610eSPierre Jolivet . header   - additional header information, may be `NULL`
25204102261SBarry Smith . ctype    - data type of body, for example application/json
25304102261SBarry Smith . body     - data to send to server
254811af0c4SBarry Smith . sock     - obtained with `PetscOpenSocket()`
25504102261SBarry Smith - buffsize - size of buffer
25604102261SBarry Smith 
25704102261SBarry Smith   Output Parameter:
25804102261SBarry Smith . buff - everything returned from server
2594683183fSBarry Smith 
2604683183fSBarry Smith   Level: advanced
2614683183fSBarry Smith 
262db781477SPatrick Sanan .seealso: `PetscHTTPSRequest()`, `PetscOpenSocket()`, `PetscHTTPSConnect()`, `PetscPullJSONValue()`
2634683183fSBarry Smith @*/
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 PetscErrorCode PetscHTTPRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], int sock, char buff[], size_t buffsize)
265d71ae5a4SJacob Faibussowitsch {
26604102261SBarry Smith   char  *request;
26704102261SBarry Smith   size_t request_len;
26804102261SBarry Smith 
26904102261SBarry Smith   PetscFunctionBegin;
2709566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type, url, header, ctype, body, &request));
2719566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
27204102261SBarry Smith 
2739566063dSJacob Faibussowitsch   PetscCall(PetscBinaryWrite(sock, request, request_len, PETSC_CHAR));
2749566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
2750298d37cSMatthew G. Knepley   PetscCall(PetscBinaryRead(sock, buff, buffsize, NULL, PETSC_CHAR));
27604102261SBarry Smith   buff[buffsize - 1] = 0;
2779566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTP result follows: \n%s\n", buff));
2783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27904102261SBarry Smith }
28004102261SBarry Smith 
2814683183fSBarry Smith /*@C
2824683183fSBarry Smith   PetscHTTPSConnect - connect to a HTTPS server
2834683183fSBarry Smith 
2844683183fSBarry Smith   Input Parameters:
2854683183fSBarry Smith + host - the name of the machine hosting the HTTPS server
2864683183fSBarry Smith . port - the port number where the server is hosting, usually 443
287811af0c4SBarry Smith - ctx  - value obtained with `PetscSSLInitializeContext()`
2884683183fSBarry Smith 
2894683183fSBarry Smith   Output Parameters:
2904683183fSBarry Smith + sock - socket to connect
291811af0c4SBarry Smith - ssl  - the argument passed to `PetscHTTPSRequest()`
2924683183fSBarry Smith 
2934683183fSBarry Smith   Level: advanced
2944683183fSBarry Smith 
295db781477SPatrick Sanan .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`
2964683183fSBarry Smith @*/
PetscHTTPSConnect(const char host[],int port,SSL_CTX * ctx,int * sock,SSL ** ssl)297d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHTTPSConnect(const char host[], int port, SSL_CTX *ctx, int *sock, SSL **ssl)
298d71ae5a4SJacob Faibussowitsch {
299b967cddfSBarry Smith   BIO *sbio;
300b967cddfSBarry Smith 
301b967cddfSBarry Smith   PetscFunctionBegin;
302b967cddfSBarry Smith   /* Connect the TCP socket*/
3039566063dSJacob Faibussowitsch   PetscCall(PetscOpenSocket(host, port, sock));
304b967cddfSBarry Smith 
305b967cddfSBarry Smith   /* Connect the SSL socket */
306b967cddfSBarry Smith   *ssl = SSL_new(ctx);
307b967cddfSBarry Smith   sbio = BIO_new_socket(*sock, BIO_NOCLOSE);
308b967cddfSBarry Smith   SSL_set_bio(*ssl, sbio, sbio);
30908401ef6SPierre Jolivet   PetscCheck(SSL_connect(*ssl) > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL connect error");
3103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
311b967cddfSBarry Smith }
312b967cddfSBarry Smith 
3134683183fSBarry Smith /*@C
3144683183fSBarry Smith   PetscPullJSONValue - Given a JSON response containing the substring with "key" : "value"  where there may or not be spaces around the : returns the value.
3154683183fSBarry Smith 
3164683183fSBarry Smith   Input Parameters:
3174683183fSBarry Smith + buff     - the char array containing the possible values
3184683183fSBarry Smith . key      - the key of the requested value
3194683183fSBarry Smith - valuelen - the length of the array to contain the value associated with the key
3204683183fSBarry Smith 
3214683183fSBarry Smith   Output Parameters:
3224683183fSBarry Smith + value - the value obtained
3234683183fSBarry Smith - found - flag indicating if the value was found in the buff
3244683183fSBarry Smith 
3254683183fSBarry Smith   Level: advanced
3264683183fSBarry Smith 
327811af0c4SBarry Smith .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`, `PetscPushJSONValue()`
3284683183fSBarry Smith @*/
PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool * found)329d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPullJSONValue(const char buff[], const char key[], char value[], size_t valuelen, PetscBool *found)
330d71ae5a4SJacob Faibussowitsch {
33168e69593SBarry Smith   char  *v, *w;
33268e69593SBarry Smith   char   work[256];
33368e69593SBarry Smith   size_t len;
33468e69593SBarry Smith 
33568e69593SBarry Smith   PetscFunctionBegin;
336c6a7a370SJeremy L Thompson   PetscCall(PetscStrncpy(work, "\"", sizeof(work)));
3379566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(work, key, sizeof(work)));
338c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(work, "\":", sizeof(work)));
3399566063dSJacob Faibussowitsch   PetscCall(PetscStrstr(buff, work, &v));
3409566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(work, &len));
34168e69593SBarry Smith   if (v) {
34268e69593SBarry Smith     v += len;
34368e69593SBarry Smith   } else {
34468e69593SBarry Smith     work[len++ - 1] = 0;
345c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(work, " :", sizeof(work)));
3469566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, work, &v));
34768e69593SBarry Smith     if (!v) {
34868e69593SBarry Smith       *found = PETSC_FALSE;
3493ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
35068e69593SBarry Smith     }
35168e69593SBarry Smith     v += len;
35268e69593SBarry Smith   }
3539566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v, '\"', &v));
35468e69593SBarry Smith   if (!v) {
35568e69593SBarry Smith     *found = PETSC_FALSE;
3563ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
35768e69593SBarry Smith   }
3589566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v + 1, '\"', &w));
35968e69593SBarry Smith   if (!w) {
36068e69593SBarry Smith     *found = PETSC_FALSE;
3613ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
36268e69593SBarry Smith   }
36368e69593SBarry Smith   *found = PETSC_TRUE;
3649566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(value, v + 1, PetscMin((size_t)(w - v), valuelen)));
3653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36668e69593SBarry Smith }
3675dc0f0a4SBarry Smith 
3685dc0f0a4SBarry Smith #include <ctype.h>
3695dc0f0a4SBarry Smith 
3704683183fSBarry Smith /*@C
3714683183fSBarry Smith   PetscPushJSONValue -  Puts a "key" : "value" pair onto a string
3725dc0f0a4SBarry Smith 
3734683183fSBarry Smith   Input Parameters:
374aec76313SJacob Faibussowitsch + buff    - the char array where the value will be put
3754683183fSBarry Smith . key     - the key value to be set
3764683183fSBarry Smith . value   - the value associated with the key
3774683183fSBarry Smith - bufflen - the size of the buffer (currently ignored)
3784683183fSBarry Smith 
3794683183fSBarry Smith   Level: advanced
3804683183fSBarry Smith 
381811af0c4SBarry Smith   Note:
38295452b02SPatrick Sanan   Ignores lengths so can cause buffer overflow
383811af0c4SBarry Smith 
384811af0c4SBarry Smith .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`, `PetscPullJSONValue()`
3854683183fSBarry Smith @*/
PetscPushJSONValue(char buff[],const char key[],const char value[],size_t bufflen)386d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPushJSONValue(char buff[], const char key[], const char value[], size_t bufflen)
387d71ae5a4SJacob Faibussowitsch {
3885dc0f0a4SBarry Smith   size_t    len;
3895dc0f0a4SBarry Smith   PetscBool special;
3905dc0f0a4SBarry Smith 
3915dc0f0a4SBarry Smith   PetscFunctionBegin;
3929566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(value, "null", &special));
39348a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcmp(value, "true", &special));
39448a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcmp(value, "false", &special));
3955dc0f0a4SBarry Smith   if (!special) {
3965dc0f0a4SBarry Smith     PetscInt i;
3975dc0f0a4SBarry Smith 
3989566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(value, &len));
3995dc0f0a4SBarry Smith     special = PETSC_TRUE;
4005dc0f0a4SBarry Smith     for (i = 0; i < (int)len; i++) {
4015dc0f0a4SBarry Smith       if (!isdigit(value[i])) {
4025dc0f0a4SBarry Smith         special = PETSC_FALSE;
4035dc0f0a4SBarry Smith         break;
4045dc0f0a4SBarry Smith       }
4055dc0f0a4SBarry Smith     }
4065dc0f0a4SBarry Smith   }
4075dc0f0a4SBarry Smith 
408c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, "\"", bufflen));
409c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, key, bufflen));
410c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, "\":", bufflen));
411c6a7a370SJeremy L Thompson   if (!special) PetscCall(PetscStrlcat(buff, "\"", bufflen));
412c6a7a370SJeremy L Thompson   PetscCall(PetscStrlcat(buff, value, bufflen));
413c6a7a370SJeremy L Thompson   if (!special) PetscCall(PetscStrlcat(buff, "\"", bufflen));
4143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4155dc0f0a4SBarry Smith }
416