mirror of https://github.com/apache/cloudstack.git
1) Make generic dao be able to persist UTF-8 string for internationalization support
2) Undo gson Unicode escape in API response object to avoid double escaping which can break Javascript from getting correct text content 3) Correct API layer in dealing with character encoding 4) Remove double escape in cloud.core.js
This commit is contained in:
parent
fa9c882d8c
commit
54f177cacc
|
|
@ -11,7 +11,6 @@
|
|||
<classpathentry kind="lib" path="/thirdparty/commons-pool-1.4.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/ehcache-1.5.0.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/junit-4.8.1.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/xenserver-5.6.0-1.jar" sourcepath="/thirdparty/XenServerJava"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/trilead-ssh2-build213.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/commons-httpclient-3.1.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/commons-codec-1.4.jar"/>
|
||||
|
|
@ -39,5 +38,6 @@
|
|||
<classpathentry kind="lib" path="/thirdparty/vmware-vim.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/vmware-vim25.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/gson.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/xenserver-5.5.0-1.jar" sourcepath="/thirdparty/xen/XenServerJava"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@
|
|||
<classpathentry kind="lib" path="/thirdparty/email.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/junit-4.8.1.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/commons-codec-1.4.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/xenserver-5.6.0-1.jar" sourcepath="/thirdparty/XenServerJava"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/xmlrpc-client-3.1.3.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/xmlrpc-client-3.1.3.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/xmlrpc-common-3.1.3.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/servlet-api.jar"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/api"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/trilead-ssh2-build213.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/xstream-1.3.1.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/gson.jar"/>
|
||||
<classpathentry kind="lib" path="/thirdparty/xenserver-5.5.0-1.jar" sourcepath="/thirdparty/xen/XenServerJava"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
|
|||
|
|
@ -14,3 +14,4 @@ public class ApiGsonHelper {
|
|||
return s_gBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -274,9 +274,9 @@ public class ApiServer implements HttpRequestHandler {
|
|||
response.setStatusCode(se.getErrorCode());
|
||||
response.setReasonPhrase(se.getDescription());
|
||||
BasicHttpEntity body = new BasicHttpEntity();
|
||||
body.setContentType("text/xml; charset=UTF-8");
|
||||
body.setContentType("text/xml");
|
||||
String responseStr = "<error>"+se.getErrorCode()+" : "+se.getDescription()+"</error>";
|
||||
body.setContent(new ByteArrayInputStream(responseStr.getBytes()));
|
||||
body.setContent(new ByteArrayInputStream(responseStr.getBytes("UTF-8")));
|
||||
response.setEntity(body);
|
||||
|
||||
sb.append(" " + se.getErrorCode() + " " + responseStr.length());
|
||||
|
|
@ -714,19 +714,19 @@ public class ApiServer implements HttpRequestHandler {
|
|||
BasicHttpEntity body = new BasicHttpEntity();
|
||||
if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) {
|
||||
// JSON response
|
||||
body.setContentType("text/javascript; charset=UTF-8");
|
||||
body.setContentType("text/javascript");
|
||||
if (responseText == null) {
|
||||
body.setContent(new ByteArrayInputStream("{ \"error\" : { \"description\" : \"Internal Server Error\" } }".getBytes()));
|
||||
body.setContent(new ByteArrayInputStream("{ \"error\" : { \"description\" : \"Internal Server Error\" } }".getBytes("UTF-8")));
|
||||
}
|
||||
} else {
|
||||
body.setContentType("text/xml; charset=UTF-8");
|
||||
body.setContentType("text/xml");
|
||||
if (responseText == null) {
|
||||
body.setContent(new ByteArrayInputStream("<error>Internal Server Error</error>".getBytes()));
|
||||
body.setContent(new ByteArrayInputStream("<error>Internal Server Error</error>".getBytes("UTF-8")));
|
||||
}
|
||||
}
|
||||
|
||||
if (responseText != null) {
|
||||
body.setContent(new ByteArrayInputStream(responseText.getBytes()));
|
||||
body.setContent(new ByteArrayInputStream(responseText.getBytes("UTF-8")));
|
||||
}
|
||||
resp.setEntity(body);
|
||||
} catch (Exception ex) {
|
||||
|
|
|
|||
|
|
@ -320,14 +320,10 @@ public class ApiServlet extends HttpServlet {
|
|||
} else {
|
||||
resp.setContentType("text/xml");
|
||||
}
|
||||
resp.setStatus(isError? HttpServletResponse.SC_INTERNAL_SERVER_ERROR : HttpServletResponse.SC_OK);
|
||||
byte[] respBytes = response.getBytes();
|
||||
resp.setContentLength(respBytes.length);
|
||||
OutputStream os = resp.getOutputStream();
|
||||
os.write(respBytes);
|
||||
os.flush();
|
||||
os.close();
|
||||
resp.flushBuffer();
|
||||
resp.setStatus(isError? HttpServletResponse.SC_INTERNAL_SERVER_ERROR : HttpServletResponse.SC_OK);
|
||||
|
||||
// use getWriter() instead of manually manipulate encoding to have better localization support
|
||||
resp.getWriter().print(response);
|
||||
} catch (IOException ioex) {
|
||||
if (s_logger.isTraceEnabled()) {
|
||||
s_logger.trace("exception writing response: " + ioex);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ import java.lang.reflect.Field;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
|
@ -28,6 +28,16 @@ public class ApiResponseSerializer {
|
|||
return toXMLSerializedString(result);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern s_unicodeEscapePattern = Pattern.compile("\\\\u([0-9A-Fa-f]{4})");
|
||||
public static String unescape(String escaped) {
|
||||
String str = escaped;
|
||||
Matcher matcher = s_unicodeEscapePattern.matcher(str);
|
||||
while(matcher.find()) {
|
||||
str = str.replaceAll("\\" + matcher.group(0), Character.toString((char)Integer.parseInt(matcher.group(1), 16)));
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private static String toJSONSerializedString(ResponseObject result) {
|
||||
if (result != null) {
|
||||
|
|
@ -39,10 +49,12 @@ public class ApiResponseSerializer {
|
|||
List<? extends ResponseObject> responses = ((ListResponse)result).getResponses();
|
||||
if ((responses != null) && !responses.isEmpty()) {
|
||||
int count = responses.size();
|
||||
String jsonStr = gson.toJson(responses.get(0));
|
||||
String jsonStr = gson.toJson(responses.get(0));;
|
||||
jsonStr = unescape(jsonStr);
|
||||
sb.append("{ \"" + responses.get(0).getObjectName() + "\" : [ " + jsonStr);
|
||||
for (int i = 1; i < count; i++) {
|
||||
jsonStr = gson.toJson(responses.get(i));
|
||||
jsonStr = unescape(jsonStr);
|
||||
sb.append(", " + jsonStr);
|
||||
}
|
||||
sb.append(" ] }");
|
||||
|
|
@ -54,6 +66,7 @@ public class ApiResponseSerializer {
|
|||
} else {
|
||||
String jsonStr = gson.toJson(result);
|
||||
if ((jsonStr != null) && !"".equals(jsonStr)) {
|
||||
jsonStr = unescape(jsonStr);
|
||||
if (result instanceof AsyncJobResponse || result instanceof CreateCmdResponse) {
|
||||
sb.append(jsonStr);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -66,15 +66,16 @@ public class ConsoleProxyServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
|
||||
try {
|
||||
String userId = null;
|
||||
String account = null;
|
||||
Account accountObj = null;
|
||||
|
||||
|
||||
Map<String, Object[]> params = new HashMap<String, Object[]>();
|
||||
params.putAll(req.getParameterMap());
|
||||
|
||||
|
||||
HttpSession session = req.getSession(false);
|
||||
if(session == null) {
|
||||
if(verifyRequest(params)) {
|
||||
|
|
|
|||
|
|
@ -537,11 +537,11 @@ function createURL(url) {
|
|||
}
|
||||
|
||||
function fromdb(val) {
|
||||
return sanitizeXSS(unescape(noNull(val)));
|
||||
return sanitizeXSS(noNull(val));
|
||||
}
|
||||
|
||||
function todb(val) {
|
||||
return encodeURIComponent(escape(val));
|
||||
return encodeURIComponent(val);
|
||||
}
|
||||
|
||||
var midmenuItemCount = 20;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package com.cloud.utils.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
|
@ -448,7 +449,20 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
|
|||
try {
|
||||
final Class<?> type = field.getType();
|
||||
if (type == String.class) {
|
||||
field.set(entity, rs.getString(index));
|
||||
byte[] bytes = rs.getBytes(index);
|
||||
if(bytes != null) {
|
||||
try {
|
||||
field.set(entity, new String(bytes, "UTF-8"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
assert(false);
|
||||
throw new CloudRuntimeException("IllegalArgumentException when converting UTF-8 data");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
assert(false);
|
||||
throw new CloudRuntimeException("UnsupportedEncodingException when converting UTF-8 data");
|
||||
}
|
||||
} else {
|
||||
field.set(entity, null);
|
||||
}
|
||||
} else if (type == long.class) {
|
||||
field.setLong(entity, rs.getLong(index));
|
||||
} else if (type == Long.class) {
|
||||
|
|
@ -560,7 +574,16 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
|
|||
@DB(txn=false) @SuppressWarnings("unchecked")
|
||||
protected <M> M getObject(Class<M> type, ResultSet rs, int index) throws SQLException {
|
||||
if (type == String.class) {
|
||||
return (M)rs.getString(index);
|
||||
byte[] bytes = rs.getBytes(index);
|
||||
if(bytes != null) {
|
||||
try {
|
||||
return (M)new String(bytes, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new CloudRuntimeException("UnsupportedEncodingException exception while converting UTF-8 data");
|
||||
}
|
||||
} else {
|
||||
return (M)null;
|
||||
}
|
||||
} else if (type == int.class) {
|
||||
return (M)new Integer(rs.getInt(index));
|
||||
} else if (type == Integer.class) {
|
||||
|
|
@ -1197,10 +1220,23 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
|
|||
final Column column = attr.field.getAnnotation(Column.class);
|
||||
final int length = column != null ? column.length() : 255;
|
||||
|
||||
// to support generic localization, utilize MySql UTF-8 support
|
||||
if (length < str.length()) {
|
||||
pstmt.setString(j, str.substring(0, column.length()));
|
||||
try {
|
||||
pstmt.setBytes(j, str.substring(0, column.length()).getBytes("UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// no-way it can't support UTF-8 encoding
|
||||
assert(false);
|
||||
throw new CloudRuntimeException("UnsupportedEncodingException when saving string as UTF-8 data");
|
||||
}
|
||||
} else {
|
||||
pstmt.setString(j, str);
|
||||
try {
|
||||
pstmt.setBytes(j, str.getBytes("UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// no-way it can't support UTF-8 encoding
|
||||
assert(false);
|
||||
throw new CloudRuntimeException("UnsupportedEncodingException when saving string as UTF-8 data");
|
||||
}
|
||||
}
|
||||
} else if (attr.field.getType() == Date.class) {
|
||||
final Date date = (Date)value;
|
||||
|
|
|
|||
Loading…
Reference in New Issue