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

Reply via email to