url.c (5633B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "url.h" 21 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25 26/** 27 * Returns whether the given character is a character that need not be 28 * escaped when included as part of a component of a URL. 29 * 30 * @param c 31 * The character to test. 32 * 33 * @return 34 * Zero if the character does not need to be escaped when included as 35 * part of a component of a URL, non-zero otherwise. 36 */ 37static int guac_kubernetes_is_url_safe(char c) { 38 return (c >= 'A' && c <= 'Z') 39 || (c >= 'a' && c <= 'z') 40 || (c >= '0' && c <= '9') 41 || strchr("-_.!~*'()", c) != NULL; 42} 43 44int guac_kubernetes_escape_url_component(char* output, int length, 45 const char* str) { 46 47 char* current = output; 48 while (*str != '\0') { 49 50 char c = *str; 51 52 /* Store alphanumeric characters verbatim */ 53 if (guac_kubernetes_is_url_safe(c)) { 54 55 /* Verify space exists for single character */ 56 if (length < 1) 57 return 1; 58 59 *(current++) = c; 60 length--; 61 62 } 63 64 /* Escape EVERYTHING else as hex */ 65 else { 66 67 /* Verify space exists for hex-encoded character */ 68 if (length < 4) 69 return 1; 70 71 snprintf(current, 4, "%%%02X", (int) c); 72 73 current += 3; 74 length -= 3; 75 } 76 77 /* Next character */ 78 str++; 79 80 } 81 82 /* Verify space exists for null terminator */ 83 if (length < 1) 84 return 1; 85 86 /* Append null terminator */ 87 *current = '\0'; 88 return 0; 89 90} 91 92int guac_kubernetes_append_endpoint_param(char* buffer, int length, 93 const char* param_name, const char* param_value) { 94 95 char escaped_param_value[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH]; 96 97 /* Escape value */ 98 if (guac_kubernetes_escape_url_component(escaped_param_value, 99 sizeof(escaped_param_value), param_value)) 100 return 1; 101 102 char* str = buffer; 103 104 int str_len = 0; 105 int qmark = 0; 106 107 while (*str != '\0') { 108 109 /* Look for a question mark */ 110 if (*str=='?') qmark = 1; 111 112 /* Compute the buffer string length */ 113 str_len++; 114 115 /* Verify the buffer null terminated */ 116 if (str_len >= length) return 1; 117 118 /* Next character */ 119 str++; 120 } 121 122 /* Determine the parameter delimiter */ 123 char delimiter = '?'; 124 if (qmark) delimiter = '&'; 125 126 /* Advance to end of buffer, where the new parameter and delimiter need to 127 * be appended */ 128 buffer += str_len; 129 length -= str_len; 130 131 /* Write the parameter and delimiter to the buffer */ 132 int written = snprintf(buffer, length, "%c%s=%s", delimiter, 133 param_name, escaped_param_value); 134 135 /* The parameter was successfully added if it was written to the given 136 * buffer without truncation */ 137 return (written < 0 || written >= length); 138} 139 140int guac_kubernetes_endpoint_uri(char* buffer, int length, 141 const char* kubernetes_namespace, const char* kubernetes_pod, 142 const char* kubernetes_container, const char* exec_command) { 143 144 char escaped_namespace[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH]; 145 char escaped_pod[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH]; 146 147 /* Escape Kubernetes namespace */ 148 if (guac_kubernetes_escape_url_component(escaped_namespace, 149 sizeof(escaped_namespace), kubernetes_namespace)) 150 return 1; 151 152 /* Escape name of Kubernetes pod */ 153 if (guac_kubernetes_escape_url_component(escaped_pod, 154 sizeof(escaped_pod), kubernetes_pod)) 155 return 1; 156 157 /* Determine the call type */ 158 char* call = "attach"; 159 if (exec_command != NULL) 160 call = "exec"; 161 162 int written; 163 164 /* Generate the endpoint path and write to the buffer */ 165 written = snprintf(buffer, length, 166 "/api/v1/namespaces/%s/pods/%s/%s", escaped_namespace, escaped_pod, call); 167 168 /* Operation successful if the endpoint path was written to the given 169 * buffer without truncation */ 170 if (written < 0 || written >= length) 171 return 1; 172 173 /* Append exec command parameter */ 174 if (exec_command != NULL) { 175 if (guac_kubernetes_append_endpoint_param(buffer, 176 length, "command", exec_command)) 177 return 1; 178 } 179 180 /* Append kubernetes container parameter */ 181 if (kubernetes_container != NULL) { 182 if (guac_kubernetes_append_endpoint_param(buffer, 183 length, "container", kubernetes_container)) 184 return 1; 185 } 186 187 /* Append stdin, stdout and tty parameters */ 188 return (guac_kubernetes_append_endpoint_param(buffer, length, "stdin", "true")) 189 || (guac_kubernetes_append_endpoint_param(buffer, length, "stdout", "true")) 190 || (guac_kubernetes_append_endpoint_param(buffer, length, "tty", "true")); 191}