1 2 #include <petscwebclient.h> 3 4 static BIO *bio_err = NULL; 5 6 #define PASSWORD "password" 7 8 #if defined(PETSC_USE_SSL_CERTIFICATE) 9 static int password_cb(char *buf,int num, int rwflag,void *userdata) 10 { 11 if (num < strlen(PASSWORD)+1) return(0); 12 strcpy(buf,PASSWORD); 13 return(strlen(PASSWORD)); 14 } 15 #endif 16 17 static void sigpipe_handle(int x) 18 { 19 } 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "PetscSSLInitializeContext" 23 /* 24 PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests. 25 26 If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with 27 28 $ saws/CA.pl -newcert (using the passphrase of password) 29 $ cat newkey.pem newcert.pem > sslclient.pem 30 31 and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 32 silly but it was all I could figure out. 33 34 */ 35 PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) 36 { 37 SSL_CTX *ctx; 38 #if defined(PETSC_USE_SSL_CERTIFICATE) 39 char keyfile[PETSC_MAX_PATH_LEN]; 40 PetscBool exists; 41 PetscErrorCode ierr; 42 #endif 43 44 PetscFunctionBegin; 45 if (!bio_err){ 46 SSL_library_init(); 47 SSL_load_error_strings(); 48 bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 49 } 50 51 /* Set up a SIGPIPE handler */ 52 signal(SIGPIPE,sigpipe_handle); 53 54 ctx = SSL_CTX_new(SSLv23_method()); 55 56 #if defined(PETSC_USE_SSL_CERTIFICATE) 57 /* Locate keyfile */ 58 ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 59 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 60 if (!exists) { 61 ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 62 ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 63 ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 64 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 65 if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 66 } 67 68 /* Load our keys and certificates*/ 69 if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file"); 70 71 SSL_CTX_set_default_passwd_cb(ctx,password_cb); 72 if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file"); 73 #endif 74 75 *octx = ctx; 76 PetscFunctionReturn(0); 77 } 78 79 #undef __FUNCT__ 80 #define __FUNCT__ "PetscSSLDestroyContext" 81 PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) 82 { 83 PetscFunctionBegin; 84 SSL_CTX_free(ctx); 85 PetscFunctionReturn(0); 86 } 87 88 #undef __FUNCT__ 89 #define __FUNCT__ "PetscHTTPBuildRequest" 90 PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest) 91 { 92 char *request=0; 93 char contentlength[40],contenttype[80],*path,*host; 94 size_t request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0; 95 PetscErrorCode ierr; 96 PetscBool flg; 97 98 PetscFunctionBegin; 99 ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr); 100 ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr); 101 if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url); 102 *path = 0; 103 ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr); 104 105 ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr); 106 ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr); 107 108 if (header) { 109 ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 110 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 111 } 112 113 ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 114 if (ctype) { 115 ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 116 ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 117 } 118 ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 119 ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 120 ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 121 ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 122 123 /* Now construct our HTTP request */ 124 request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1; 125 ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 126 ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 127 ierr = PetscStrcat(request," ");CHKERRQ(ierr); 128 ierr = PetscStrcat(request,path);CHKERRQ(ierr); 129 ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr); 130 ierr = PetscStrcat(request,host);CHKERRQ(ierr); 131 ierr = PetscFree(host);CHKERRQ(ierr); 132 ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 133 ierr = PetscStrcat(request,header);CHKERRQ(ierr); 134 if (ctype) { 135 ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 136 } 137 ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 138 ierr = PetscStrcat(request,body);CHKERRQ(ierr); 139 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 140 ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 141 142 *outrequest = request; 143 PetscFunctionReturn(0); 144 } 145 146 147 #undef __FUNCT__ 148 #define __FUNCT__ "PetscHTTPSRequest" 149 /* 150 PetscHTTPSRequest - Send a request to an HTTPS server 151 152 Input Parameters: 153 + type - either "POST" or "GET" 154 . url - URL of request host/path 155 . header - additional header information, may be NULL 156 . ctype - data type of body, for example application/json 157 . body - data to send to server 158 . ssl - obtained with PetscHTTPSConnect() 159 - buffsize - size of buffer 160 161 Output Parameter: 162 . buff - everything returned from server 163 */ 164 PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize) 165 { 166 char *request; 167 int r; 168 size_t request_len,len; 169 PetscErrorCode ierr; 170 171 PetscFunctionBegin; 172 ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 173 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 174 175 r = SSL_write(ssl,request,(int)request_len); 176 switch (SSL_get_error(ssl,r)){ 177 case SSL_ERROR_NONE: 178 if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 179 break; 180 default: 181 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 182 } 183 184 /* Now read the server's response, assuming that it's terminated by a close */ 185 r = SSL_read(ssl,buff,(int)buffsize); 186 len = r; 187 switch (SSL_get_error(ssl,r)){ 188 case SSL_ERROR_NONE: 189 break; 190 case SSL_ERROR_ZERO_RETURN: 191 SSL_shutdown(ssl); /* ignore shutdown error message */ 192 break; 193 case SSL_ERROR_SYSCALL: 194 break; 195 default: 196 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 197 } 198 buff[len] = 0; /* null terminate string */ 199 ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 200 201 SSL_free(ssl); 202 ierr = PetscFree(request);CHKERRQ(ierr); 203 PetscFunctionReturn(0); 204 } 205 206 #undef __FUNCT__ 207 #define __FUNCT__ "PetscHTTPRequest" 208 /* 209 PetscHTTPRequest - Send a request to an HTTP server 210 211 Input Parameters: 212 + type - either "POST" or "GET" 213 . url - URL of request host/path 214 . header - additional header information, may be NULL 215 . ctype - data type of body, for example application/json 216 . body - data to send to server 217 . sock - obtained with PetscOpenSocket() 218 - buffsize - size of buffer 219 220 Output Parameter: 221 . buff - everything returned from server 222 */ 223 PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize) 224 { 225 char *request; 226 size_t request_len; 227 PetscErrorCode ierr; 228 229 PetscFunctionBegin; 230 ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 231 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 232 233 ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr); 234 ierr = PetscFree(request);CHKERRQ(ierr); 235 PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR); 236 buff[buffsize-1] = 0; 237 ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr); 238 PetscFunctionReturn(0); 239 } 240 241 #undef __FUNCT__ 242 #define __FUNCT__ "PetscHTTPSConnect" 243 PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 244 { 245 BIO *sbio; 246 PetscErrorCode ierr; 247 248 PetscFunctionBegin; 249 /* Connect the TCP socket*/ 250 ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 251 252 /* Connect the SSL socket */ 253 *ssl = SSL_new(ctx); 254 sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 255 SSL_set_bio(*ssl,sbio,sbio); 256 if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 257 PetscFunctionReturn(0); 258 } 259 260 #undef __FUNCT__ 261 #define __FUNCT__ "PetscPullJSONValue" 262 /* 263 Given a JSON response containing the substring with "key" : "value" where there may or not be spaces around the : returns the value. 264 */ 265 PetscErrorCode PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool *found) 266 { 267 PetscErrorCode ierr; 268 char *v,*w; 269 char work[256]; 270 size_t len; 271 272 PetscFunctionBegin; 273 ierr = PetscStrcpy(work,"\"");CHKERRQ(ierr); 274 ierr = PetscStrncat(work,key,250);CHKERRQ(ierr); 275 ierr = PetscStrcat(work,"\":");CHKERRQ(ierr); 276 ierr = PetscStrstr(buff,work,&v);CHKERRQ(ierr); 277 ierr = PetscStrlen(work,&len);CHKERRQ(ierr); 278 if (v) { 279 v += len; 280 } else { 281 work[len++-1] = 0; 282 ierr = PetscStrcat(work," :");CHKERRQ(ierr); 283 ierr = PetscStrstr(buff,work,&v);CHKERRQ(ierr); 284 if (!v) { 285 *found = PETSC_FALSE; 286 PetscFunctionReturn(0); 287 } 288 v += len; 289 } 290 ierr = PetscStrchr(v,'\"',&v);CHKERRQ(ierr); 291 if (!v) { 292 *found = PETSC_FALSE; 293 PetscFunctionReturn(0); 294 } 295 ierr = PetscStrchr(v+1,'\"',&w);CHKERRQ(ierr); 296 if (!w) { 297 *found = PETSC_FALSE; 298 PetscFunctionReturn(0); 299 } 300 *found = PETSC_TRUE; 301 ierr = PetscStrncpy(value,v+1,PetscMin(w-v,valuelen));CHKERRQ(ierr); 302 PetscFunctionReturn(0); 303 } 304