feat(landerctl): support posting redirects
							parent
							
								
									49c4c78242
								
							
						
					
					
						commit
						810bfd2bc9
					
				|  | @ -1 +1,2 @@ | |||
| api_key = test | ||||
| server_url = http://localhost:18080 | ||||
|  |  | |||
|  | @ -1,8 +1,13 @@ | |||
| #ifndef LANDERCTL | ||||
| #define LANDERCTL | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #include <curl/curl.h> | ||||
| 
 | ||||
| typedef struct landerctl_cfg { | ||||
|   const char *api_key; | ||||
|   const char *server_url; | ||||
| } landerctl_cfg; | ||||
| 
 | ||||
| typedef enum landerctl_cfg_err { | ||||
|  | @ -20,4 +25,18 @@ typedef enum landerctl_cfg_err { | |||
|  */ | ||||
| landerctl_cfg_err landerctl_cfg_parse(landerctl_cfg *out, const char *path); | ||||
| 
 | ||||
| typedef enum landerctl_mode { | ||||
|   landerctl_mode_none = 0, | ||||
|   landerctl_mode_short, | ||||
|   landerctl_mode_paste, | ||||
|   landerctl_mode_file, | ||||
| } landerctl_mode; | ||||
| 
 | ||||
| struct curl_slist *landerctl_set_common(const landerctl_cfg *cfg, CURL *curl, | ||||
|                                         landerctl_mode mode, bool secure, | ||||
|                                         const char *key); | ||||
| void landerctl_post_short(CURL *curl, const char *url); | ||||
| void landerctl_post_paste(CURL *curl, const char *path); | ||||
| void landerctl_post_file(CURL *curl, const char *path); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -14,12 +14,27 @@ landerctl_cfg_err landerctl_cfg_parse(landerctl_cfg *out, const char *path) { | |||
|     return landerctl_cfg_err_not_found; | ||||
|   } | ||||
| 
 | ||||
|   struct { | ||||
|     const char *key; | ||||
|     const char **var; | ||||
|   } key_to_vars[] = { | ||||
|       {"api_key", &out->api_key}, | ||||
|       {"server_url", &out->server_url}, | ||||
|   }; | ||||
|   size_t key_to_vars_len = sizeof(key_to_vars) / sizeof(key_to_vars[0]); | ||||
| 
 | ||||
|   // We NULL everything beforehand so we can check if we have all needed
 | ||||
|   // variables
 | ||||
|   for (size_t i = 0; i < key_to_vars_len; i++) { | ||||
|     *key_to_vars[i].var = NULL; | ||||
|   } | ||||
| 
 | ||||
|   regex_t cfg_line_regex; | ||||
|   regcomp(&cfg_line_regex, cfg_line_regex_expr, REG_EXTENDED); | ||||
| 
 | ||||
|   // Accept lines of at most 256 lines
 | ||||
|   char line[256]; | ||||
|   landerctl_cfg_err res = landerctl_cfg_err_incomplete; | ||||
|   landerctl_cfg_err res = landerctl_cfg_err_ok; | ||||
| 
 | ||||
|   while (fgets(line, sizeof(line), f) != NULL) { | ||||
|     // Last character might be a newline
 | ||||
|  | @ -38,18 +53,29 @@ landerctl_cfg_err landerctl_cfg_parse(landerctl_cfg *out, const char *path) { | |||
|     } | ||||
| 
 | ||||
|     // api_key is currently the only value we parse
 | ||||
|     int key_len = reg_groups[1].rm_eo - reg_groups[1].rm_so; | ||||
|     size_t key_len = reg_groups[1].rm_eo - reg_groups[1].rm_so; | ||||
| 
 | ||||
|     if ((strlen("api_key") == key_len) && | ||||
|         (strncmp("api_key", &line[reg_groups[1].rm_so], key_len) == 0)) { | ||||
|       int val_len = reg_groups[2].rm_eo - reg_groups[2].rm_so; | ||||
|       char *buf = malloc(val_len + 1); | ||||
|       strncpy(buf, &line[reg_groups[2].rm_so], val_len); | ||||
|     for (size_t i = 0; i < key_to_vars_len; i++) { | ||||
|       if ((key_len == strlen(key_to_vars[i].key)) && | ||||
|           (strncmp(&line[reg_groups[1].rm_so], key_to_vars[i].key, key_len) == | ||||
|            0)) { | ||||
|         int val_len = reg_groups[2].rm_eo - reg_groups[2].rm_so; | ||||
|         char *buf = malloc(val_len + 1); | ||||
|         strncpy(buf, &line[reg_groups[2].rm_so], val_len); | ||||
|         buf[val_len] = '\0'; | ||||
| 
 | ||||
|       out->api_key = buf; | ||||
|         *key_to_vars[i].var = buf; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|       res = landerctl_cfg_err_ok; | ||||
|       break; | ||||
|   if (res == landerctl_cfg_err_ok) { | ||||
|     for (size_t i = 0; i < key_to_vars_len; i++) { | ||||
|       if (*key_to_vars[i].var == NULL) { | ||||
|         res = landerctl_cfg_err_incomplete; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sys/stat.h> | ||||
|  | @ -8,7 +9,8 @@ | |||
| 
 | ||||
| #include "landerctl.h" | ||||
| 
 | ||||
| const char default_cfg_path[] = ".landerrc"; | ||||
| const char *default_cfg_path = ".landerrc"; | ||||
| const char *usage = "%s [-SPFsv] arg [key]\n"; | ||||
| 
 | ||||
| int main(int argc, char **argv) { | ||||
|   landerctl_cfg cfg; | ||||
|  | @ -33,6 +35,99 @@ int main(int argc, char **argv) { | |||
|     exit(1); | ||||
|   } | ||||
| 
 | ||||
|   opterr = 0; | ||||
| 
 | ||||
|   int c; | ||||
|   landerctl_mode mode = landerctl_mode_none; | ||||
|   bool secure = false; | ||||
|   bool verbose = false; | ||||
| 
 | ||||
|   while ((c = getopt(argc, argv, "SPFsv")) != -1) { | ||||
|     switch (c) { | ||||
|     case 'S': | ||||
|       mode = landerctl_mode_short; | ||||
|       break; | ||||
|     case 'P': | ||||
|       mode = landerctl_mode_paste; | ||||
|       break; | ||||
|     case 'F': | ||||
|       mode = landerctl_mode_file; | ||||
|       break; | ||||
|     case 's': | ||||
|       secure = true; | ||||
|       break; | ||||
|     case 'v': | ||||
|       verbose = true; | ||||
|       break; | ||||
|     case '?': | ||||
|       printf(usage, argv[0]); | ||||
|       exit(2); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (mode == landerctl_mode_none) { | ||||
|     printf("No mode specified.\n\n"); | ||||
|     printf(usage, argv[0]); | ||||
|     exit(2); | ||||
|   } | ||||
| 
 | ||||
|   if (optind == argc || (argc - optind > 2)) { | ||||
|     printf(usage, argv[0]); | ||||
|     exit(2); | ||||
|   } | ||||
| 
 | ||||
|   const char *arg = argv[optind]; | ||||
|   const char *key = argc - optind == 2 ? argv[optind + 1] : NULL; | ||||
| 
 | ||||
|   curl_global_init(CURL_GLOBAL_ALL); | ||||
|   CURL *curl = curl_easy_init(); | ||||
| 
 | ||||
|   if (curl == NULL) { | ||||
|     exit(255); | ||||
|   } | ||||
| 
 | ||||
|   struct curl_slist *list = landerctl_set_common(&cfg, curl, mode, secure, key); | ||||
| 
 | ||||
|   switch (mode) { | ||||
|   case landerctl_mode_short: | ||||
|     landerctl_post_short(curl, arg); | ||||
|     break; | ||||
|   } | ||||
| 
 | ||||
|   if (verbose) { | ||||
|     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); | ||||
|   } | ||||
| 
 | ||||
|   int exit_code = 0; | ||||
| 
 | ||||
|   if (curl_easy_perform(curl) == CURLE_OK) { | ||||
|     long response_code; | ||||
|     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); | ||||
| 
 | ||||
|     if (response_code < 200 || response_code > 299) { | ||||
|       fprintf(stderr, "HTTP status code %li\n", response_code); | ||||
|       exit_code = 3; | ||||
|     } else { | ||||
|       struct curl_header *location_header; | ||||
| 
 | ||||
|       if (curl_easy_header(curl, "Location", 0, CURLH_HEADER, -1, | ||||
|                            &location_header) == CURLHE_OK) { | ||||
|         printf("%s%s\n", cfg.server_url, location_header->value); | ||||
|       } else { | ||||
|         fprintf(stderr, "Server returned a 2xx without a Location header.\n"); | ||||
|         exit_code = 5; | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     fprintf(stderr, "Libcurl encountered an error.\n"); | ||||
|     exit_code = 4; | ||||
|   } | ||||
| 
 | ||||
|   curl_easy_cleanup(curl); | ||||
|   curl_slist_free_all(list); | ||||
| 
 | ||||
|   return exit_code; | ||||
| 
 | ||||
|   /* struct stat sb; */ | ||||
| 
 | ||||
|   /* stat(argv[1], &sb); */ | ||||
|  | @ -46,8 +141,6 @@ int main(int argc, char **argv) { | |||
|   /*   exit(1); */ | ||||
|   /* } */ | ||||
| 
 | ||||
|   /* curl_global_init(CURL_GLOBAL_ALL); */ | ||||
| 
 | ||||
|   /* CURL *curl = curl_easy_init(); */ | ||||
| 
 | ||||
|   /* if (curl == NULL) { */ | ||||
|  |  | |||
|  | @ -0,0 +1,60 @@ | |||
| #include <curl/curl.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include "landerctl.h" | ||||
| 
 | ||||
| struct curl_slist *landerctl_set_common(const landerctl_cfg *cfg, CURL *curl, | ||||
|                                         landerctl_mode mode, bool secure, | ||||
|                                         const char *key) { | ||||
|   size_t url_len = strlen(cfg->server_url) + 4; | ||||
| 
 | ||||
|   if (key != NULL) { | ||||
|     url_len += strlen(key); | ||||
|   } | ||||
| 
 | ||||
|   char mode_char; | ||||
| 
 | ||||
|   switch (mode) { | ||||
|   case landerctl_mode_short: | ||||
|     mode_char = 's'; | ||||
|     break; | ||||
|   case landerctl_mode_paste: | ||||
|     mode_char = 'p'; | ||||
|     break; | ||||
|   case landerctl_mode_file: | ||||
|     mode_char = 'f'; | ||||
|     break; | ||||
|   // Shouldn't be able  to happen
 | ||||
|   default: | ||||
|     return NULL; | ||||
|   } | ||||
| 
 | ||||
|   char url[url_len + 1]; | ||||
| 
 | ||||
|   if (key == NULL) { | ||||
|     sprintf(url, "%s/%c%s/", cfg->server_url, mode_char, secure ? "l" : ""); | ||||
|   } else { | ||||
|     sprintf(url, "%s/%c%s/%s", cfg->server_url, mode_char, secure ? "l" : "", | ||||
|             key); | ||||
|   } | ||||
| 
 | ||||
|   curl_easy_setopt(curl, CURLOPT_URL, url); | ||||
| 
 | ||||
|   // Add API key header
 | ||||
|   char api_key_header[strlen(cfg->api_key) + 12]; | ||||
|   sprintf(api_key_header, "X-Api-Key: %s", cfg->api_key); | ||||
| 
 | ||||
|   struct curl_slist *list = NULL; | ||||
|   list = curl_slist_append(list, api_key_header); | ||||
| 
 | ||||
|   curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); | ||||
| 
 | ||||
|   curl_easy_setopt(curl, CURLOPT_USERAGENT, "landerctl/" LANDER_VERSION ""); | ||||
| 
 | ||||
|   return list; | ||||
| } | ||||
| 
 | ||||
| void landerctl_post_short(CURL *curl, const char *url) { | ||||
|   curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(url)); | ||||
|   curl_easy_setopt(curl, CURLOPT_POSTFIELDS, url); | ||||
| } | ||||
		Loading…
	
		Reference in New Issue