1. 03 Sep 2012

    jetty处理 http response header中文字符,调试笔记

    这段时间,我和几个同事在做另外一个美味书签,一个没有选辑,专注收藏的服务,和有选辑的美味书签并存。

    大家讨论,觉得url应该是尽量清晰简单。比如张三用户登陆,它的url是/u/张三,之类的。能让高级用户直接输入url。url是可读的。

    我们的程序用clojure开发。用ring,compojure, jetty。

    我遇到了一个问题,在jetty返回给浏览器的http header中, 中文成了乱码。

    场景如下:

    1. 张三到达我们网站,他在美味书签的用户名也是张三,输入的网址是landing page的 url: http://meiweisq.com/
    2. 程序发现,此用户已经登陆过,redirect到他的首页 /u/张三
    3. 浏览器看见的却是 /u/??

    在第2和第3步之间出问题了。jetty在encode

    {
         :status 302
         :headers {"Location" "/u/张三"}
         :body nil
         }

    时出现乱码。尝试各种方法无果。

    无奈之下换上我手工写的一个ring adapter, 发现也出现乱码,赶快修改了encode header相关代码, 从ASCII改为UTF8,问题解决。

    但这只是一个临时的解决方法。

    下班回家后,还在琢磨这件事, download了jetty的代码:

    git clone git://github.com/eclipse/jetty.project.git

    checkout 我们用的相应版本7.6.1.v20120215。

    经过一番查找,调试,发现了问题所在, jetty在encode http response header时,用了hardcode的 ISO-8859-1

    这段代码是用来encode http header的:

    // ./jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
    // 322行到347行
      private Buffer convertValue(String value)
        {
            Buffer buffer = __cache.get(value);
            if (buffer!=null)
                return buffer;
    
            try
            {
                buffer = new ByteArrayBuffer(value,StringUtil.__ISO_8859_1);
    
                if (__cacheSize>0)
                {
                    if (__cache.size()>__cacheSize)
                        __cache.clear();
                    Buffer b=__cache.putIfAbsent(value,buffer);
                    if (b!=null)
                        buffer=b;
                }
    
                return buffer;
            }
            catch (UnsupportedEncodingException e)
            {
                throw new RuntimeException(e);
            }
        }

    StringUtil.__ISO_8859_1的定义

    // ./jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
    
        public static final String __ISO_8859_1="ISO-8859-1";
        public final static String __UTF8="UTF-8";
        public final static String __UTF8Alt="UTF8";
        public final static String __UTF16="UTF-16";

    解决办法

    {
    :status 302
    :headers {"Location" (URLEncoder/encode "/u/张三")}
    :body nil
    }

    后面想到可以用另外的方式绕过jetty编码http header的问题:

    • 返回一个网页,网页里面用js
    location.href="/u/张三"
     http-equiv="refresh" content="0;URL='/u/张三'">
  2. 30 Jun 2012

    Rssminer public beta

    Rssminer is a simple online RSS reader written in Clojure, Java, Javascript.

    Feature

    • Not Feature rich, just a central place to reading RSS news.
    • Concise UI.
    • Read the orignal article, which may include valuable comments.
    • Learing from reading history, rank all articles accordingly.
    • Fast, Instant full text search.

    A brief history

    1. Initially, I randly pick a project to experiment one page javascript APP, client side unit testing. A RSS reader is choosen by accident.
    2. Backbone is tried, I even read several times. , got read several times.
    3. Function and Object literal are the best parts of Javascript. They complement each other. Backbone fail to utilize them efficiently.
    4. I did many expriments and thinking. By dropping Backone.js, take my brain as the backone, structure the code the way I like it, I found a better world.
    5. Writing javascript is fun. Writing Clojure is fun. Clojure mixed with JAVA is really great. They make me continue doing this project.
    6. Rssminer is born.

    Performance

    I like fast application. In order to be fast,

    • The application is carefully designed .
    • A WEB server, written from scratch to power Rssminer, to achieve low lantency.
    • A HTTP Client, written from scratch to power the fetcher module.
    • A fast Template. With it, I can easily pack the minified CSS with the HTML to save a network round trip. It bootstrap the application.
    • Browser talks to server in JSON. Render HTML in browser side achieves even better performance.
    • Powered by Redis and MySQL

    Demo

    A demo account is created: http://rssminer.net/demo. Feel free to try it. Feedbacks are welcome.

    Open Source

    https://github.com/shenfeng/rssminer

  3. 22 Jun 2012

    About Javascript dispatch event and delegate event

    (function () {
      var all_events = {};          // events data, private to this file
      function bind_event (ele, event, handler) {
        if(ele.addEventListener) {
          ele.addEventListener(event, handler, false);
        } else {                    // ie
          ele.attachEvent('on' + event, handler);
        }
      }
      // a Simple impl of dispatch event.
      function dispatch_event (ele, selector, eventName, handler) {
        var handlers = all_events[ele] || {};
        if(handlers[eventName]) {
          handlers[eventName].push(handler); // add more
        } else {
          handlers[eventName] = [handler]; // register
          var one_handler = function (e) {
            // find registerd handlers
            var handlers = (all_events[ele] || {})[eventName];
            if(!handlers) { return; }
            var target = e.target;
            // IE6, IE7 does not support querySelectorAll
            var nodes = ele.querySelectorAll(selector);
            for(var i = 0; i < nodes.length; i++) {
              // interested event hanpend on interested DOM node
              if(nodes[i] === target) {
                for(var j = 0; j < handlers.length; j++) { // call one by one
                  // properly bind `this`
                  var ret = handlers[j].apply(target, [e]);
                  if(ret === false) {
                    e.preventDefault(); e.stopPropagation();
                  }
                }
              }
            }
          };
          bind_event(ele, eventName, one_handler);
        }
        all_events[ele] = handlers;
      }
      var EVENTSPLITTER = /^(\S+)\s*(.*)$/;
      // extracted from Backbone.js, brilliant
      function delegate_events (ele, events) {
        for (var key in events) {
          var method = events[key],
              match = key.match(EVENTSPLITTER),
              eventName = match[1],
              selector = match[2];
          if (selector === '') {
            bind_event(ele, eventName, method);
          } else {
            dispatch_event(ele, selector, eventName, method);
          }
        }
      }
      function click_handler1 () { console.log('click', this, e); }
      function click_handler2 () { console.log('click2', this, e); }
      // I like the syntax.
      // And it's very flexable, modify the DOM as you want,
      // event handler will work just the way you want it
      delegate_events(document, {
        'click li': click_handler1,
        'click ul li': click_handler2
      });
    })();
  4. 06 Apr 2012

    jvm options

    java -XX:+PrintFlagsFinal

  5. 27 Mar 2012

    2012要看的书, 要写的代码

    管2012会不会有不有世界末日, 他并不妨碍我读几本书。

    作为一个程序员,行业要求要无止境的学习,并且我还很喜欢这个行业

    • 《深入理解Java虚拟机:JVM高级特性与最佳实践》 不管怎样, 我很喜欢java和JVM上的Clojure, 有必要深入了解一下。
    • 《Computer Systems, A programmer’s perspective》 去年就开始翻了, 希望今年能看完。
    • 《The c programming language》 大一就读了这本书, 现在有必要重读一下

    • 《a global history from prehistory to the 21st century》 袁某人推荐的。去年就买了,可是没有看。 很是喜欢袁老师

    想要写的代码

    • 用C写一个Web Server, 用epoll,自己写内存分配,妥善处理超时,和各种意 外情况。 看看能到多快。

    • 用纯JAVA, 从头写一个web server 和http client,给Rssminer用。 能给 production用。 妥善处理超时, 各种意外,控制latency, 控制内存使用。
    • 写完Rssminer。 这个已经写了快一年了。 今年6月份以前应该publicly available