xref: /petsc/src/sys/webclient/client.c (revision 041022618293821dae82bc1c7413cd3666530fdf)
1b967cddfSBarry Smith 
20efc6a03SBarry Smith #include <petscwebclient.h>
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)
9b967cddfSBarry Smith static int password_cb(char *buf,int num, int rwflag,void *userdata)
10b967cddfSBarry Smith {
11b967cddfSBarry Smith   if (num < strlen(PASSWORD)+1) return(0);
12b967cddfSBarry Smith   strcpy(buf,PASSWORD);
13b967cddfSBarry Smith   return(strlen(PASSWORD));
14b967cddfSBarry Smith }
15b967cddfSBarry Smith #endif
16b967cddfSBarry Smith 
17b967cddfSBarry Smith static void sigpipe_handle(int x)
18b967cddfSBarry Smith {
19b967cddfSBarry Smith }
20b967cddfSBarry Smith 
21b967cddfSBarry Smith #undef __FUNCT__
22b967cddfSBarry Smith #define __FUNCT__ "PetscSSLInitializeContext"
23b967cddfSBarry Smith /*
24b967cddfSBarry Smith     PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
25b967cddfSBarry Smith 
264a285bdaSBarry Smith     If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with
27b967cddfSBarry Smith 
28b967cddfSBarry Smith $    ./CA.pl  -newcert  (using the passphrase of password)
29b967cddfSBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
30b967cddfSBarry Smith 
31b967cddfSBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
32b967cddfSBarry Smith     silly but it was all I could figure out.
33b967cddfSBarry Smith 
34b967cddfSBarry Smith */
35b967cddfSBarry Smith PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
36b967cddfSBarry Smith {
37b967cddfSBarry Smith     SSL_METHOD     *meth;
38b967cddfSBarry Smith     SSL_CTX        *ctx;
394a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
40b967cddfSBarry Smith     char           keyfile[PETSC_MAX_PATH_LEN];
41b967cddfSBarry Smith     PetscBool      exists;
42b967cddfSBarry Smith     PetscErrorCode ierr;
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 
55b967cddfSBarry Smith     meth = SSLv23_method();
56b967cddfSBarry Smith     ctx  = SSL_CTX_new(meth);
57b967cddfSBarry Smith 
584a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
59b967cddfSBarry Smith     /* Locate keyfile */
60b967cddfSBarry Smith     ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr);
61b967cddfSBarry Smith     ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
62b967cddfSBarry Smith     if (!exists) {
63b967cddfSBarry Smith       ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
64b967cddfSBarry Smith       ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr);
65b967cddfSBarry Smith       ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr);
66b967cddfSBarry Smith       ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
67b967cddfSBarry Smith       if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory");
68b967cddfSBarry Smith     }
69b967cddfSBarry Smith 
70b967cddfSBarry Smith     /* Load our keys and certificates*/
71b967cddfSBarry Smith     if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file");
72b967cddfSBarry Smith 
73b967cddfSBarry Smith     SSL_CTX_set_default_passwd_cb(ctx,password_cb);
74b967cddfSBarry Smith     if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file");
75b967cddfSBarry Smith #endif
76b967cddfSBarry Smith 
77b967cddfSBarry Smith     *octx = ctx;
78b967cddfSBarry Smith     PetscFunctionReturn(0);
79b967cddfSBarry Smith }
80b967cddfSBarry Smith 
81b967cddfSBarry Smith #undef __FUNCT__
82b967cddfSBarry Smith #define __FUNCT__ "PetscSSLDestroyContext"
83b967cddfSBarry Smith PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
84b967cddfSBarry Smith {
85b967cddfSBarry Smith   PetscFunctionBegin;
86b967cddfSBarry Smith   SSL_CTX_free(ctx);
87b967cddfSBarry Smith   PetscFunctionReturn(0);
88b967cddfSBarry Smith }
89b967cddfSBarry Smith 
90b967cddfSBarry Smith #undef __FUNCT__
91*04102261SBarry Smith #define __FUNCT__ "PetscHTTPBuildRequest"
92*04102261SBarry Smith PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest)
93b967cddfSBarry Smith {
94b967cddfSBarry Smith   char           *request=0;
9593e1d32fSBarry Smith   char           contentlength[40],contenttype[80],*path,*host;
96b967cddfSBarry Smith   int            r;
9793e1d32fSBarry Smith   size_t         request_len,len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0;
98b967cddfSBarry Smith   PetscErrorCode ierr;
99b967cddfSBarry Smith   PetscBool      flg;
100b967cddfSBarry Smith 
101b967cddfSBarry Smith   PetscFunctionBegin;
10293e1d32fSBarry Smith   ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr);
10393e1d32fSBarry Smith   ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr);
10493e1d32fSBarry Smith   if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url);
10593e1d32fSBarry Smith   *path = NULL;
10693e1d32fSBarry Smith   ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr);
10793e1d32fSBarry Smith 
10893e1d32fSBarry Smith   ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr);
10993e1d32fSBarry Smith   ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr);
11093e1d32fSBarry Smith 
111b967cddfSBarry Smith   if (header) {
112b967cddfSBarry Smith     ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr);
113b967cddfSBarry Smith     if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n");
114b967cddfSBarry Smith   }
115b967cddfSBarry Smith 
116b967cddfSBarry Smith   ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr);
117b967cddfSBarry Smith   if (ctype) {
118b967cddfSBarry Smith     ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr);
119b967cddfSBarry Smith     ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr);
120b967cddfSBarry Smith   }
121b967cddfSBarry Smith   ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr);
122b967cddfSBarry Smith   ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr);
123b967cddfSBarry Smith   ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr);
124b967cddfSBarry Smith   ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr);
125b967cddfSBarry Smith 
126b967cddfSBarry Smith   /* Now construct our HTTP request */
12793e1d32fSBarry Smith   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
128fe278a28SBarry Smith   ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr);
129b967cddfSBarry Smith   ierr = PetscStrcpy(request,type);CHKERRQ(ierr);
130b967cddfSBarry Smith   ierr = PetscStrcat(request," ");CHKERRQ(ierr);
13193e1d32fSBarry Smith   ierr = PetscStrcat(request,path);CHKERRQ(ierr);
13293e1d32fSBarry Smith   ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr);
13393e1d32fSBarry Smith   ierr = PetscStrcat(request,host);CHKERRQ(ierr);
13493e1d32fSBarry Smith   ierr = PetscFree(host);CHKERRQ(ierr);
13593e1d32fSBarry Smith   ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr);
136b967cddfSBarry Smith   ierr = PetscStrcat(request,header);CHKERRQ(ierr);
137b967cddfSBarry Smith   if (ctype) {
138b967cddfSBarry Smith     ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr);
139b967cddfSBarry Smith   }
140b967cddfSBarry Smith   ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr);
141b967cddfSBarry Smith   ierr = PetscStrcat(request,body);CHKERRQ(ierr);
142b967cddfSBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
143b967cddfSBarry Smith   ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr);
144b967cddfSBarry Smith 
145*04102261SBarry Smith   *outrequest = request;
146*04102261SBarry Smith   PetscFunctionReturn(0);
147*04102261SBarry Smith }
148*04102261SBarry Smith 
149*04102261SBarry Smith 
150*04102261SBarry Smith #undef __FUNCT__
151*04102261SBarry Smith #define __FUNCT__ "PetscHTTPSRequest"
152*04102261SBarry Smith /*
153*04102261SBarry Smith      PetscHTTPSRequest - Send a request to an HTTPS server
154*04102261SBarry Smith 
155*04102261SBarry Smith    Input Parameters:
156*04102261SBarry Smith +   type - either "POST" or "GET"
157*04102261SBarry Smith .   url -  URL of request host/path
158*04102261SBarry Smith .   header - additional header information, may be NULL
159*04102261SBarry Smith .   ctype - data type of body, for example application/json
160*04102261SBarry Smith .   body - data to send to server
161*04102261SBarry Smith .   ssl - obtained with PetscHTTPSConnect()
162*04102261SBarry Smith -   buffsize - size of buffer
163*04102261SBarry Smith 
164*04102261SBarry Smith    Output Parameter:
165*04102261SBarry Smith .   buff - everything returned from server
166*04102261SBarry Smith  */
167*04102261SBarry Smith PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize)
168*04102261SBarry Smith {
169*04102261SBarry Smith   char           *request;
170*04102261SBarry Smith   int            r;
171*04102261SBarry Smith   size_t         request_len,len;
172*04102261SBarry Smith   PetscErrorCode ierr;
173*04102261SBarry Smith 
174*04102261SBarry Smith   PetscFunctionBegin;
175*04102261SBarry Smith   ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr);
176*04102261SBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
177*04102261SBarry Smith 
178b967cddfSBarry Smith   r = SSL_write(ssl,request,request_len);
179b967cddfSBarry Smith   switch (SSL_get_error(ssl,r)){
180b967cddfSBarry Smith     case SSL_ERROR_NONE:
181b967cddfSBarry Smith       if (request_len != r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket");
182b967cddfSBarry Smith       break;
183b967cddfSBarry Smith     default:
184b967cddfSBarry Smith       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem");
185b967cddfSBarry Smith   }
186b967cddfSBarry Smith 
187b967cddfSBarry Smith   /* Now read the server's response, assuming  that it's terminated by a close */
188b967cddfSBarry Smith   r = SSL_read(ssl,buff,(int)buffsize);
189b967cddfSBarry Smith   len = r;
190b967cddfSBarry Smith   switch (SSL_get_error(ssl,r)){
191b967cddfSBarry Smith   case SSL_ERROR_NONE:
192b967cddfSBarry Smith     break;
193b967cddfSBarry Smith   case SSL_ERROR_ZERO_RETURN:
194b967cddfSBarry Smith     SSL_shutdown(ssl);  /* ignore shutdown error message */
195b967cddfSBarry Smith     break;
196b967cddfSBarry Smith   case SSL_ERROR_SYSCALL:
197b967cddfSBarry Smith     break;
198b967cddfSBarry Smith   default:
199b967cddfSBarry Smith     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem");
200b967cddfSBarry Smith   }
201b967cddfSBarry Smith   buff[len] = 0; /* null terminate string */
202b967cddfSBarry Smith   ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr);
203b967cddfSBarry Smith 
204b967cddfSBarry Smith   SSL_free(ssl);
205b967cddfSBarry Smith   ierr = PetscFree(request);CHKERRQ(ierr);
206b967cddfSBarry Smith   PetscFunctionReturn(0);
207b967cddfSBarry Smith }
208b967cddfSBarry Smith 
209b967cddfSBarry Smith #undef __FUNCT__
210*04102261SBarry Smith #define __FUNCT__ "PetscHTTPRequest"
211*04102261SBarry Smith /*
212*04102261SBarry Smith      PetscHTTPRequest - Send a request to an HTTP server
213*04102261SBarry Smith 
214*04102261SBarry Smith    Input Parameters:
215*04102261SBarry Smith +   type - either "POST" or "GET"
216*04102261SBarry Smith .   url -  URL of request host/path
217*04102261SBarry Smith .   header - additional header information, may be NULL
218*04102261SBarry Smith .   ctype - data type of body, for example application/json
219*04102261SBarry Smith .   body - data to send to server
220*04102261SBarry Smith .   sock - obtained with PetscOpenSocket()
221*04102261SBarry Smith -   buffsize - size of buffer
222*04102261SBarry Smith 
223*04102261SBarry Smith    Output Parameter:
224*04102261SBarry Smith .   buff - everything returned from server
225*04102261SBarry Smith  */
226*04102261SBarry Smith PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize)
227*04102261SBarry Smith {
228*04102261SBarry Smith   char           *request;
229*04102261SBarry Smith   size_t         request_len;
230*04102261SBarry Smith   PetscErrorCode ierr;
231*04102261SBarry Smith 
232*04102261SBarry Smith   PetscFunctionBegin;
233*04102261SBarry Smith   ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr);
234*04102261SBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
235*04102261SBarry Smith 
236*04102261SBarry Smith   ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
237*04102261SBarry Smith   ierr = PetscFree(request);CHKERRQ(ierr);
238*04102261SBarry Smith   PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR);
239*04102261SBarry Smith   buff[buffsize-1] = 0;
240*04102261SBarry Smith   ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr);
241*04102261SBarry Smith   PetscFunctionReturn(0);
242*04102261SBarry Smith }
243*04102261SBarry Smith 
244*04102261SBarry Smith 
245*04102261SBarry Smith #undef __FUNCT__
246b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSConnect"
247b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl)
248b967cddfSBarry Smith {
249b967cddfSBarry Smith   BIO            *sbio;
250b967cddfSBarry Smith   PetscErrorCode ierr;
251b967cddfSBarry Smith 
252b967cddfSBarry Smith   PetscFunctionBegin;
253b967cddfSBarry Smith   /* Connect the TCP socket*/
254b967cddfSBarry Smith   ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr);
255b967cddfSBarry Smith 
256b967cddfSBarry Smith   /* Connect the SSL socket */
257b967cddfSBarry Smith   *ssl = SSL_new(ctx);
258b967cddfSBarry Smith   sbio = BIO_new_socket(*sock,BIO_NOCLOSE);
259b967cddfSBarry Smith   SSL_set_bio(*ssl,sbio,sbio);
260b967cddfSBarry Smith   if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error");
261b967cddfSBarry Smith   PetscFunctionReturn(0);
262b967cddfSBarry Smith }
263b967cddfSBarry Smith 
264