Author: sveinung Date: Fri Aug 28 12:54:21 2015 New Revision: 29703 URL: http://svn.gna.org/viewcvs/freeciv?rev=29703&view=rev Log: JSON protocol: support URI encoded strings
Freeciv-web escapes some, but not all, strings using URI encoding. Introduce a new dataio type estring. In the JSON protocol the estring is an URI encoded string. In the raw protocol it forwards to the string dataio type without encoding anything at all. Should the need to escape something, like the C string terminator, appear a raw protocol implementation can be added later. Thanks to Andreas Røsdal <andreasr> for pointing out that CURL does URI encoding and decoding. See patch #6295 Modified: trunk/common/dataio.h trunk/common/dataio_json.c trunk/common/dataio_json.h trunk/common/generate_packets.py Modified: trunk/common/dataio.h URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/dataio.h?rev=29703&r1=29702&r2=29703&view=diff ============================================================================== --- trunk/common/dataio.h (original) +++ trunk/common/dataio.h Fri Aug 28 12:54:21 2015 @@ -148,6 +148,10 @@ bool dio_get_uint16_vec8_raw(struct data_in *din, int **values, int stop_value) fc__attribute((nonnull (2))); +/* There is currently no need to escape strings in the binary protocol. */ +#define dio_get_estring_raw dio_get_string_raw +#define dio_put_estring_raw dio_put_string_raw + #ifndef FREECIV_JSON_CONNECTION /* Should be a function but we need some macro magic. */ Modified: trunk/common/dataio_json.c URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/dataio_json.c?rev=29703&r1=29702&r2=29703&view=diff ============================================================================== --- trunk/common/dataio_json.c (original) +++ trunk/common/dataio_json.c Fri Aug 28 12:54:21 2015 @@ -24,6 +24,8 @@ #endif #ifdef FREECIV_JSON_CONNECTION + +#include <curl/curl.h> #include <limits.h> #include <math.h> @@ -90,6 +92,23 @@ #endif /************************************************************************** + Returns a CURL easy handle for name encoding and decoding +**************************************************************************/ +static CURL *get_curl(void) +{ + static CURL *curl_easy_handle = NULL; + + if (curl_easy_handle == NULL) { + curl_easy_handle = curl_easy_init(); + } else { + /* Reuse the existing CURL easy handle */ + curl_easy_reset(curl_easy_handle); + } + + return curl_easy_handle; +} + +/************************************************************************** Returns FALSE if the destination isn't large enough or the source was bad. This is default get_conv_callback. **************************************************************************/ @@ -582,6 +601,25 @@ } /************************************************************************** + Encode and write the specified string to the specified location. +**************************************************************************/ +void dio_put_estring_json(struct json_data_out *dout, char *key, + const struct plocation* location, + const char *value) +{ + char *escaped_value; + + /* Let CURL find the length it self by passing 0 */ + escaped_value = curl_easy_escape(get_curl(), value, 0); + + /* Handle as a regular string from now on. */ + dio_put_string_json(dout, key, location, escaped_value); + + /* CURL's memory management wants to free this it self. */ + curl_free(escaped_value); +} + +/************************************************************************** ... **************************************************************************/ void dio_put_tech_list_json(struct json_data_out *dout, char *key, @@ -798,4 +836,40 @@ return TRUE; } +/************************************************************************** + Read and decode the string in the specified location. + + max_dest_size applies to both the encoded and to the decoded string. +**************************************************************************/ +bool dio_get_estring_json(json_t *json_packet, char *key, + const struct plocation* location, + char *dest, size_t max_dest_size) +{ + char *escaped_value; + char *unescaped_value; + + /* The encoded string has the same size limit as the decoded string. */ + escaped_value = fc_malloc(max_dest_size); + + if (!dio_get_string_json(json_packet, key, location, + escaped_value, max_dest_size)) { + /* dio_get_string_json() has logged this already. */ + return FALSE; + } + + /* Let CURL find the length it self by passing 0 */ + unescaped_value = curl_easy_unescape(get_curl(), escaped_value, 0, NULL); + + /* Done with the escaped value. */ + FC_FREE(escaped_value); + + /* Copy the unescaped value so CURL can free its own copy. */ + memcpy(dest, unescaped_value, max_dest_size); + + /* CURL's memory management wants to free this it self. */ + curl_free(unescaped_value); + + return TRUE; +} + #endif /* FREECIV_JSON_CONNECTION */ Modified: trunk/common/dataio_json.h URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/dataio_json.h?rev=29703&r1=29702&r2=29703&view=diff ============================================================================== --- trunk/common/dataio_json.h (original) +++ trunk/common/dataio_json.h Fri Aug 28 12:54:21 2015 @@ -77,6 +77,9 @@ bool dio_get_string_json(json_t *json_packet, char *key, const struct plocation* location, char *dest, size_t max_dest_size); +bool dio_get_estring_json(json_t *json_packet, char *key, + const struct plocation* location, + char *dest, size_t max_dest_size); bool dio_get_tech_list_json(json_t *json_packet, char *key, const struct plocation* location, int *dest); bool dio_get_unit_list_json(json_t *json_packet, char *key, @@ -142,6 +145,9 @@ void dio_put_string_json(struct json_data_out *dout, char *key, const struct plocation* location, const char *value); +void dio_put_estring_json(struct json_data_out *dout, char *key, + const struct plocation* location, + const char *value); void dio_put_city_map_json(struct json_data_out *dout, char *key, const struct plocation* location, const char *value); Modified: trunk/common/generate_packets.py URL: http://svn.gna.org/viewcvs/freeciv/trunk/common/generate_packets.py?rev=29703&r1=29702&r2=29703&view=diff ============================================================================== --- trunk/common/generate_packets.py (original) +++ trunk/common/generate_packets.py Fri Aug 28 12:54:21 2015 @@ -220,7 +220,7 @@ return result def get_handle_type(self): - if self.dataio_type=="string": + if self.dataio_type=="string" or self.dataio_type=="estring": return "const char *" if self.dataio_type=="worklist": return "const %s *"%self.struct_type @@ -245,7 +245,7 @@ return " worklist_copy(&real_packet->%(name)s, %(name)s);"%self.__dict__ if self.is_array==0: return " real_packet->%(name)s = %(name)s;"%self.__dict__ - if self.dataio_type=="string": + if self.dataio_type=="string" or self.dataio_type=="estring": return " sz_strlcpy(real_packet->%(name)s, %(name)s);"%self.__dict__ if self.is_array==1: tmp="real_packet->%(name)s[i] = %(name)s[i]"%self.__dict__ @@ -266,14 +266,14 @@ return " differ = (memcmp(old->%(name)s, real_packet->%(name)s, %(array_size_d)s) != 0);"%self.__dict__ if self.dataio_type=="bitvector": return " differ = !BV_ARE_EQUAL(old->%(name)s, real_packet->%(name)s);"%self.__dict__ - if self.dataio_type in ["string"] and self.is_array==1: + if self.dataio_type in ["string", "estring"] and self.is_array==1: return " differ = (strcmp(old->%(name)s, real_packet->%(name)s) != 0);"%self.__dict__ if self.is_struct and self.is_array==0: return " differ = !are_%(dataio_type)ss_equal(&old->%(name)s, &real_packet->%(name)s);"%self.__dict__ if not self.is_array: return " differ = (old->%(name)s != real_packet->%(name)s);"%self.__dict__ - if self.dataio_type=="string": + if self.dataio_type=="string" or self.dataio_type=="estring": c="strcmp(old->%(name)s[i], real_packet->%(name)s[i]) != 0"%self.__dict__ array_size_u=self.array_size1_u array_size_o=self.array_size1_o @@ -367,7 +367,7 @@ if self.dataio_type in ["memory"]: return " DIO_PUT(%(dataio_type)s, &dout, \"%(name)s\", &field_addr, &real_packet->%(name)s, %(array_size_u)s);"%self.__dict__ - arr_types=["string","city_map","tech_list", + arr_types=["string","estring","city_map","tech_list", "unit_list","building_list"] if (self.dataio_type in arr_types and self.is_array==1) or \ (self.dataio_type not in arr_types and self.is_array==0): @@ -377,7 +377,7 @@ c="DIO_PUT(%(dataio_type)s, &dout, namestr, &field_addr, &real_packet->%(name)s[i][j]);"%self.__dict__ else: c="DIO_PUT(%(dataio_type)s, &dout, namestr, &field_addr, &real_packet->%(name)s[i]);"%self.__dict__ - elif self.dataio_type=="string": + elif self.dataio_type=="string" or self.dataio_type=="estring": c="DIO_PUT(%(dataio_type)s, &dout, namestr, &field_addr, real_packet->%(name)s[i]);"%self.__dict__ array_size_u=self.array_size1_u @@ -393,7 +393,8 @@ c="DIO_PUT(%(dataio_type)s, &dout, namestr, &field_addr, real_packet->%(name)s[i]);"%self.__dict__ if not self.diff: - if self.is_array==2 and self.dataio_type!="string": + if self.is_array==2 and self.dataio_type!="string" \ + and self.dataio_type!="estring": return ''' { int i, j; @@ -576,7 +577,7 @@ return '''if (!DIO_BV_GET(&din, \"%(name)s\", &field_addr, real_packet->%(name)s)) { RECEIVE_PACKET_FIELD_ERROR(%(name)s); }'''%self.__dict__ - if self.dataio_type in ["string","city_map"] and \ + if self.dataio_type in ["string","estring","city_map"] and \ self.is_array!=2: return '''if (!DIO_GET(%(dataio_type)s, &din, \"%(name)s\", &field_addr, real_packet->%(name)s, sizeof(real_packet->%(name)s))) { RECEIVE_PACKET_FIELD_ERROR(%(name)s); @@ -613,7 +614,7 @@ c='''if (!DIO_GET(%(dataio_type)s, &din, namestr, &field_addr, &real_packet->%(name)s[i])) { RECEIVE_PACKET_FIELD_ERROR(%(name)s); }'''%self.__dict__ - elif self.dataio_type=="string": + elif self.dataio_type=="string" or self.dataio_type=="estring": c='''if (!DIO_GET(%(dataio_type)s, &din, namestr, &field_addr, real_packet->%(name)s[i], sizeof(real_packet->%(name)s[i]))) { RECEIVE_PACKET_FIELD_ERROR(%(name)s); }'''%self.__dict__ @@ -674,7 +675,8 @@ if (!DIO_GET(%(dataio_type)s, &din, \"%(name)s\", &field_addr, real_packet->%(name)s, %(array_size_u)s)){ RECEIVE_PACKET_FIELD_ERROR(%(name)s); }'''%self.get_dict(vars()) - elif self.is_array==2 and self.dataio_type!="string": + elif self.is_array==2 and self.dataio_type!="string" \ + and self.dataio_type!="estring": return ''' { int i, j; _______________________________________________ Freeciv-commits mailing list Freeciv-commits@gna.org https://mail.gna.org/listinfo/freeciv-commits