rack-ketai 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +122 -0
- data/VERSION +1 -0
- data/lib/rack/ketai/carrier/abstract.rb +263 -0
- data/lib/rack/ketai/carrier/au.rb +153 -0
- data/lib/rack/ketai/carrier/cidrs/au.rb +32 -0
- data/lib/rack/ketai/carrier/cidrs/docomo.rb +14 -0
- data/lib/rack/ketai/carrier/cidrs/softbank.rb +10 -0
- data/lib/rack/ketai/carrier/docomo.rb +157 -0
- data/lib/rack/ketai/carrier/emoji/ausjisstrtoemojiid.rb +1391 -0
- data/lib/rack/ketai/carrier/emoji/docomosjisstrtoemojiid.rb +759 -0
- data/lib/rack/ketai/carrier/emoji/emojidata.rb +836 -0
- data/lib/rack/ketai/carrier/emoji/emojiidtotypecast.rb +432 -0
- data/lib/rack/ketai/carrier/emoji/softbankutf8strtoemojiid.rb +1119 -0
- data/lib/rack/ketai/carrier/emoji/softbankwebcodetoutf8str.rb +499 -0
- data/lib/rack/ketai/carrier/general.rb +75 -0
- data/lib/rack/ketai/carrier/iphone.rb +16 -0
- data/lib/rack/ketai/carrier/softbank.rb +144 -0
- data/lib/rack/ketai/carrier/specs/au.rb +1 -0
- data/lib/rack/ketai/carrier/specs/docomo.rb +1 -0
- data/lib/rack/ketai/carrier/specs/softbank.rb +1 -0
- data/lib/rack/ketai/carrier.rb +18 -0
- data/lib/rack/ketai/display.rb +16 -0
- data/lib/rack/ketai/middleware.rb +36 -0
- data/lib/rack/ketai.rb +12 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/unit/au_filter_spec.rb +96 -0
- data/spec/unit/au_spec.rb +240 -0
- data/spec/unit/carrier_spec.rb +30 -0
- data/spec/unit/display_spec.rb +25 -0
- data/spec/unit/docomo_filter_spec.rb +106 -0
- data/spec/unit/docomo_spec.rb +344 -0
- data/spec/unit/emoticon_filter_spec.rb +91 -0
- data/spec/unit/filter_spec.rb +38 -0
- data/spec/unit/iphone_spec.rb +16 -0
- data/spec/unit/middleware_spec.rb +38 -0
- data/spec/unit/softbank_filter_spec.rb +133 -0
- data/spec/unit/softbank_spec.rb +200 -0
- data/spec/unit/valid_addr_spec.rb +86 -0
- data/test/spec_runner.rb +29 -0
- data/tools/generate_emoji_dic.rb +434 -0
- data/tools/update_speclist.rb +87 -0
- metadata +138 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
tools/tmp
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Yuichi Takeuchi
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
= rack-ketai: A Rack Middleware for Japanese mobile-phones
|
2
|
+
|
3
|
+
== rack-ketaiとは
|
4
|
+
携帯電話向けサイトを構築する際に役立ちそうな機能を提供する(ことが目標の)ミドルウェアです。
|
5
|
+
|
6
|
+
* 携帯電話キャリア判別
|
7
|
+
* 端末名の取得
|
8
|
+
* ユーザID、端末IDの取得
|
9
|
+
* ディスプレイ情報(サイズ、色数)の取得
|
10
|
+
* Cookie使用の可否
|
11
|
+
* キャッシュサイズの取得
|
12
|
+
* IPアドレス帯域の正当性チェック
|
13
|
+
* 入出力文字コード変換(DoCoMo、auのみ)
|
14
|
+
* 絵文字キャリア間変換
|
15
|
+
* PCでの絵文字表示(TypePadの絵文字使用)
|
16
|
+
|
17
|
+
テスト環境もまともにないので、万年αテスト中です。自己責任で、よくテストを行ってご利用下さい。
|
18
|
+
|
19
|
+
== 使えそうなRubyのバージョン
|
20
|
+
適当テストを通ったバージョンです。
|
21
|
+
|
22
|
+
CRuby 1.8.5, 1.8.6, 1.8.7, 1.9.1
|
23
|
+
|
24
|
+
JRuby 1.4.0
|
25
|
+
|
26
|
+
== 使用例
|
27
|
+
|
28
|
+
=== 携帯電話の識別
|
29
|
+
require 'rubygems'
|
30
|
+
require 'sinatra'
|
31
|
+
|
32
|
+
require 'rack/ketai'
|
33
|
+
use Rack::Ketai
|
34
|
+
|
35
|
+
get '/' do
|
36
|
+
case request.env['rack.ketai']
|
37
|
+
when Rack::Ketai::Carrier::Docomo
|
38
|
+
"こんにちは、DoCoMo世界!"
|
39
|
+
when Rack::Ketai::Carrier::Au
|
40
|
+
"こんにちは、Au世界!"
|
41
|
+
when Rack::Ketai::Carrier::Softbank
|
42
|
+
"こんにちは、Softbank世界!"
|
43
|
+
else
|
44
|
+
"こんにちは、その他の世界!"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
単に携帯電話でのアクセスか識別するのであれば、<tt>#mobile?</tt>を使います。
|
49
|
+
env['rack.ketai'].mobile?
|
50
|
+
|
51
|
+
互換性のため、携帯電話からのアクセスでないときには、特異メソッド<tt>#mobile? => false</tt>を定義した<tt>nil</tt>が設定されます。
|
52
|
+
|
53
|
+
=== 端末名の取得
|
54
|
+
env['rack.ketai'].name # => "SO903i"
|
55
|
+
|
56
|
+
=== ユーザID、端末IDの取得
|
57
|
+
各キャリアの利用者の識別に関する情報の扱いを一元化します。
|
58
|
+
これにより、携帯サイトでのユーザ認証等が容易になります。(後述のIPアドレス帯域チェックと併用すること)
|
59
|
+
ketai = env['rack.ketai']
|
60
|
+
ketai.subscriberid # ユーザID:iモードID or FOMAカード製造番号/EZ番号/x-jphone-uid
|
61
|
+
ketai.deviceid # 端末ID:端末製造番号(DoCoMo)/端末シリアル(SoftbankMobile)
|
62
|
+
ketai.ident # ユーザか端末を識別する情報(ユーザID or 端末製造番号)
|
63
|
+
|
64
|
+
=== ディスプレイ情報の取得
|
65
|
+
環境変数もしくは http://ke-tai.org/ で公開されている携帯端末スペック一覧のデータから縦横ピクセル数及び色数を取得できます。
|
66
|
+
ketai = env['rack.ketai']
|
67
|
+
display = ketai.display
|
68
|
+
display.colors # 色数 取得できなければ nil
|
69
|
+
display.width # 横サイズ 取得できなければ nil
|
70
|
+
display.height # 縦サイズ 取得できなければ nil
|
71
|
+
|
72
|
+
=== Cookie使用の可否
|
73
|
+
DoCoMoの場合はiモードブラウザ2.0、SoftBankは現行の全機種、auも全機種(WAP1.0端末はSSL通信時利用不可)っぽいのでそれを判別してくれます。(できるだけ...)
|
74
|
+
if env['rack.ketai'].supports_cookie?
|
75
|
+
# Cookie 使用可能
|
76
|
+
else
|
77
|
+
# Cookie 使用不可
|
78
|
+
end
|
79
|
+
|
80
|
+
=== キャッシュサイズの取得
|
81
|
+
環境変数や端末名からブラウザのキャッシュサイズ(Bytes)を取得します。取得できない場合は、それっぽい最小の値を返します。
|
82
|
+
env['rack.ketai'].cache_size # => 100000 (100KB)
|
83
|
+
|
84
|
+
=== IPアドレス帯域の正当性チェック
|
85
|
+
ユーザのアクセス元のIPアドレスがキャリアが公開するアドレス帯に含まれているか確認できます。
|
86
|
+
ユーザID等の偽装防止等に役立ちます。
|
87
|
+
ketai = env['rack.ketai']
|
88
|
+
unless ketai.mobile? && ketai.valid_addr?
|
89
|
+
# 携帯からのアクセスでない
|
90
|
+
end
|
91
|
+
|
92
|
+
=== 入出力文字コード変換
|
93
|
+
DoCoMoまたはauの携帯電話との通信でShift_JISを使うようになります。
|
94
|
+
Content-typeも便宜書き換えます。
|
95
|
+
|
96
|
+
=== 絵文字キャリア間変換
|
97
|
+
入力された絵文字を、emoji4unicodeによる変換テーブルを元に [e:XXX] という文字列に置き換えます。
|
98
|
+
(XXX はemoji4unicodeによる絵文字のID)
|
99
|
+
文字列に置き換えるようにしたのは、PCからの絵文字の入力・表示への対応を容易にするためです。
|
100
|
+
出力時にキャリアに応じた絵文字コードに変換します。
|
101
|
+
|
102
|
+
なお、文字コード変換及び絵文字変換を行いたくない場合は、<tt>:disable_filter</tt>オプションを設定します。
|
103
|
+
use Rack::Ketai, :disable_filter => true
|
104
|
+
|
105
|
+
=== PCでの絵文字表示
|
106
|
+
SixApartが公開している絵文字アイコン画像を別途ダウンロード・配置し、簡単なコードを追加することで携帯キャリア以外でのアクセスの際に絵文字画像を表示できます。
|
107
|
+
|
108
|
+
TypePadの絵文字アイコン画像と、携帯コンテンツ表示モジュールをフリー(自由)ライセンスで公開
|
109
|
+
http://start.typepad.jp/typecast/
|
110
|
+
|
111
|
+
絵文字アイコンをダウンロードし、public/images/emoticons/*.gif に配置した場合の例
|
112
|
+
use Rack::Static, :urls => ['/images'], :root => 'public'
|
113
|
+
use Rack::Ketai, :emoticons_path => '/images/emoticons'
|
114
|
+
run MyApp.new
|
115
|
+
|
116
|
+
=== 作者
|
117
|
+
|
118
|
+
Copyright 2009-2010 (c) Yuichi Takeuchi, under MIT License
|
119
|
+
|
120
|
+
Yuichi Takeuchi <mizincogrammer@gmail.com>
|
121
|
+
|
122
|
+
http://d.hatena.ne.jp/mizincogrammer
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,263 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tempfile'
|
3
|
+
require 'singleton'
|
4
|
+
require 'nkf'
|
5
|
+
require 'rack/request'
|
6
|
+
require 'stringio'
|
7
|
+
require 'ipaddr'
|
8
|
+
|
9
|
+
unless IPAddr.instance_methods.include?("to_range")
|
10
|
+
class IPAddr
|
11
|
+
|
12
|
+
def coerce_other(other)
|
13
|
+
case other
|
14
|
+
when IPAddr
|
15
|
+
other
|
16
|
+
when String
|
17
|
+
self.class.new(other)
|
18
|
+
else
|
19
|
+
self.class.new(other, @family)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the successor to the ipaddr.
|
24
|
+
def succ
|
25
|
+
return self.clone.set(@addr + 1, @family)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Compares the ipaddr with another.
|
29
|
+
def <=>(other)
|
30
|
+
other = coerce_other(other)
|
31
|
+
|
32
|
+
return nil if other.family != @family
|
33
|
+
|
34
|
+
return @addr <=> other.to_i
|
35
|
+
end
|
36
|
+
include Comparable
|
37
|
+
|
38
|
+
def to_range
|
39
|
+
begin_addr = (@addr & @mask_addr)
|
40
|
+
|
41
|
+
case @family
|
42
|
+
when Socket::AF_INET
|
43
|
+
end_addr = (@addr | (IN4MASK ^ @mask_addr))
|
44
|
+
when Socket::AF_INET6
|
45
|
+
end_addr = (@addr | (IN6MASK ^ @mask_addr))
|
46
|
+
else
|
47
|
+
raise "unsupported address family"
|
48
|
+
end
|
49
|
+
return clone.set(begin_addr, @family)..clone.set(end_addr, @family)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module Rack::Ketai::Carrier
|
56
|
+
class Abstract
|
57
|
+
|
58
|
+
class << self
|
59
|
+
def filters
|
60
|
+
[]
|
61
|
+
end
|
62
|
+
|
63
|
+
def valid_addr?(remote_addr)
|
64
|
+
cidrs = nil
|
65
|
+
begin
|
66
|
+
cidrs = self::CIDRS
|
67
|
+
rescue NameError
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
remote = IPAddr.new(remote_addr)
|
71
|
+
cidrs.any?{ |cidr| cidr.include?(remote) }
|
72
|
+
end
|
73
|
+
alias :valid_ip? :valid_addr?
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize(env)
|
77
|
+
@env = env
|
78
|
+
end
|
79
|
+
|
80
|
+
USER_AGENT_REGEXP = nil
|
81
|
+
|
82
|
+
def filtering(env, options = { }, &block)
|
83
|
+
env = options[:disable_filter] ? env : filters(options).inject(env) { |env, filter| filter.inbound(env) }
|
84
|
+
ret = block.call(env)
|
85
|
+
ret[2] = ret[2].body if ret[2].is_a?(Rack::Response)
|
86
|
+
options[:disable_filter] ? ret : filters(options).reverse.inject(ret) { |r, filter| filter.outbound(*r) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def filters(options = { })
|
90
|
+
self.class.filters.collect do |klass|
|
91
|
+
klass.new(options)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# 携帯端末か
|
96
|
+
def mobile?
|
97
|
+
false
|
98
|
+
end
|
99
|
+
|
100
|
+
# サブスクライバID
|
101
|
+
# 契約者毎にユニーク
|
102
|
+
def subscriberid
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
|
106
|
+
# デバイスID
|
107
|
+
# 端末毎にユニーク
|
108
|
+
def deviceid
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
# 識別情報
|
113
|
+
def ident
|
114
|
+
subscriberid || deviceid
|
115
|
+
end
|
116
|
+
|
117
|
+
# 機種名(略名)
|
118
|
+
def name
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
|
122
|
+
# ディスプレイ情報
|
123
|
+
def display
|
124
|
+
Rack::Ketai::Display.new
|
125
|
+
end
|
126
|
+
|
127
|
+
# キャリアのIPアドレス帯を利用しているか
|
128
|
+
def valid_addr?
|
129
|
+
self.class.valid_ip? @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_ADDR']
|
130
|
+
end
|
131
|
+
alias :valid_ip? :valid_addr?
|
132
|
+
|
133
|
+
# キャッシュサイズ
|
134
|
+
def cache_size
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
|
138
|
+
# Cookieのサポート
|
139
|
+
def supports_cookie?
|
140
|
+
false
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class Rack::Ketai::Carrier::Abstract
|
146
|
+
class Filter
|
147
|
+
|
148
|
+
def initialize(options = { })
|
149
|
+
@options = options.clone
|
150
|
+
end
|
151
|
+
|
152
|
+
def inbound(env)
|
153
|
+
apply_incoming?(env) ? to_internal(env) : env
|
154
|
+
end
|
155
|
+
|
156
|
+
def outbound(status, headers, body)
|
157
|
+
apply_outgoing?(status, headers, body) ? to_external(status, headers, body) : [status, headers, body]
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
def to_internal(env)
|
162
|
+
env
|
163
|
+
end
|
164
|
+
|
165
|
+
def to_external(status, headers, body)
|
166
|
+
if headers['Content-Type']
|
167
|
+
case headers['Content-Type']
|
168
|
+
when /charset=[\w\-]+/i
|
169
|
+
headers['Content-Type'].sub!(/charset=[\w\-]+/, 'charset=utf-8')
|
170
|
+
else
|
171
|
+
headers['Content-Type'] << "; charset=utf-8"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
[status, headers, body]
|
175
|
+
end
|
176
|
+
|
177
|
+
def full_apply(*argv, &proc)
|
178
|
+
argv.each do |obj|
|
179
|
+
deep_apply(obj, &proc)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def deep_apply(obj, &proc)
|
184
|
+
case obj
|
185
|
+
when Hash
|
186
|
+
obj.each_pair do |key, value|
|
187
|
+
obj[key] = deep_apply(value, &proc)
|
188
|
+
end
|
189
|
+
obj
|
190
|
+
when Array
|
191
|
+
obj.collect!{ |value| deep_apply(value, &proc)}
|
192
|
+
when NilClass, TrueClass, FalseClass, Tempfile, StringIO
|
193
|
+
obj
|
194
|
+
else
|
195
|
+
proc.call(obj)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def apply_incoming?(env); true; end
|
200
|
+
def apply_outgoing?(status, headers, body)
|
201
|
+
headers['Content-Type'] !~ /^(.+?)(?:;|$)/
|
202
|
+
[nil, "text/html", "application/xhtml+xml"].include?($1)
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
class SjisFilter < Filter
|
209
|
+
|
210
|
+
private
|
211
|
+
def to_internal(env)
|
212
|
+
request = Rack::Request.new(env)
|
213
|
+
|
214
|
+
# 最低でも1回呼んでないと query_string, form_hash等が未設定
|
215
|
+
request.params
|
216
|
+
|
217
|
+
# 同一オブジェクトが両方に入ってたりして二重にかかることがあるので
|
218
|
+
converted_objects = []
|
219
|
+
converter = lambda { |value|
|
220
|
+
unless converted_objects.include?(value)
|
221
|
+
value = NKF.nkf('-m0 -x -Sw', value)
|
222
|
+
converted_objects << value
|
223
|
+
end
|
224
|
+
value
|
225
|
+
}
|
226
|
+
|
227
|
+
full_apply(request.env["rack.request.query_hash"],
|
228
|
+
request.env["rack.request.form_hash"],
|
229
|
+
&converter)
|
230
|
+
|
231
|
+
request.env
|
232
|
+
end
|
233
|
+
|
234
|
+
def to_external(status, headers, body)
|
235
|
+
if body.is_a?(Array)
|
236
|
+
body = body.collect do |str|
|
237
|
+
NKF.nkf('-m0 -x -Ws', str)
|
238
|
+
end
|
239
|
+
else
|
240
|
+
body = NKF.nkf('-m0 -x -Ws', body)
|
241
|
+
end
|
242
|
+
|
243
|
+
if headers['Content-Type']
|
244
|
+
case headers['Content-Type']
|
245
|
+
when /charset=[\w\-]+/i
|
246
|
+
headers['Content-Type'].sub!(/charset=[\w\-]+/, 'charset=shift_jis')
|
247
|
+
else
|
248
|
+
headers['Content-Type'] << "; charset=shift_jis"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
content = (body.is_a?(Array) ? body[0] : body).to_s
|
253
|
+
headers['Content-Length'] = (content.respond_to?(:bytesize) ? content.bytesize : content.size).to_s if headers.member?('Content-Length')
|
254
|
+
|
255
|
+
[status, headers, body]
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
require 'rack/ketai/carrier/emoji/emojidata'
|
263
|
+
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'scanf'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
module Ketai
|
6
|
+
module Carrier
|
7
|
+
class Au < Abstract
|
8
|
+
autoload :CIDRS, 'rack/ketai/carrier/cidrs/au'
|
9
|
+
autoload :SPECS, 'rack/ketai/carrier/specs/au'
|
10
|
+
|
11
|
+
USER_AGENT_REGEXP = /^(?:KDDI|UP.Browser\/.+?)-(.+?) /
|
12
|
+
|
13
|
+
class Filter < ::Rack::Ketai::Carrier::Abstract::SjisFilter
|
14
|
+
|
15
|
+
# 絵文字コード -> 絵文字ID 対応表から、絵文字コード検出用の正規表現をつくる
|
16
|
+
# 複数の絵文字の組み合わせのものを前におくことで
|
17
|
+
# そっちを優先的にマッチさせる
|
18
|
+
def Filter.sjis_regexp
|
19
|
+
@sjis_regexp ||=
|
20
|
+
if RUBY_VERSION >= '1.9.1'
|
21
|
+
codes = EMOJI_TO_EMOJIID.keys.sort_by{ |codes| - codes.size }.collect{ |sjis| Regexp.escape(sjis)}
|
22
|
+
Regexp.new(codes.join('|'), nil)
|
23
|
+
else
|
24
|
+
codes = EMOJI_TO_EMOJIID.keys.sort_by{ |codes| - codes.size }.collect{ |sjis| Regexp.escape(sjis, 's') }
|
25
|
+
Regexp.new(codes.join('|'), nil, 's')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def to_internal(env)
|
31
|
+
# au SJISバイナリ -> 絵文字ID表記
|
32
|
+
request = Rack::Request.new(env)
|
33
|
+
|
34
|
+
request.params # 最低でも1回呼んでないと query_stringが未設定
|
35
|
+
|
36
|
+
converter = lambda do |value|
|
37
|
+
value.force_encoding('Shift_JIS') if value.respond_to?(:force_encoding)
|
38
|
+
value.gsub(Filter.sjis_regexp) do |match|
|
39
|
+
format("[e:%03X]", EMOJI_TO_EMOJIID[match])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
deep_apply(request.env["rack.request.query_hash"], &converter)
|
43
|
+
deep_apply(request.env["rack.request.form_hash"], &converter)
|
44
|
+
|
45
|
+
# 文字コード変換
|
46
|
+
super(request.env)
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_external(status, headers, body)
|
50
|
+
status, headers, body = super
|
51
|
+
|
52
|
+
return [status, headers, body] unless body[0]
|
53
|
+
|
54
|
+
body = body.collect do |str|
|
55
|
+
str.gsub(/\[e:([0-9A-F]{3})\]/) do |match|
|
56
|
+
emojiid = $1.scanf('%X').first
|
57
|
+
sjis = EMOJIID_TO_EMOJI[emojiid]
|
58
|
+
if sjis
|
59
|
+
# 絵文字があるので差替え
|
60
|
+
sjis
|
61
|
+
else
|
62
|
+
# 絵文字がないので代替文字列
|
63
|
+
emoji_data = EMOJI_DATA[emojiid]
|
64
|
+
NKF.nkf('-Ws', (emoji_data[:fallback] || emoji_data[:name] || '〓'))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
content = (body.is_a?(Array) ? body[0] : body).to_s
|
70
|
+
headers['Content-Length'] = (content.respond_to?(:bytesize) ? content.bytesize : content.size).to_s if headers.member?('Content-Length')
|
71
|
+
|
72
|
+
[status, headers, body]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class << self
|
77
|
+
def filters
|
78
|
+
super | [Rack::Ketai::Carrier::Au::Filter]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def mobile?
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
def subscriberid
|
87
|
+
ezno
|
88
|
+
end
|
89
|
+
|
90
|
+
def ezno
|
91
|
+
@ezno ||= @env['HTTP_X_UP_SUBNO'].to_s =~ /^(\w{14}_\w{2}\.ezweb\.ne\.jp)$/ && $1
|
92
|
+
end
|
93
|
+
|
94
|
+
def name
|
95
|
+
# UAの最初の - の後ろが略称
|
96
|
+
@name ||= @env['HTTP_USER_AGENT'] =~ /^[^\-]+\-(\w+)/ && $1
|
97
|
+
end
|
98
|
+
|
99
|
+
def display
|
100
|
+
return @display if @display
|
101
|
+
width = height = colors = nil
|
102
|
+
if @env['HTTP_X_UP_DEVCAP_SCREENPIXELS'].to_s =~ /(\d+),(\d+)/
|
103
|
+
width = $1.to_i
|
104
|
+
height = $2.to_i
|
105
|
+
end
|
106
|
+
width ||= spec[5]
|
107
|
+
height ||= spec[6]
|
108
|
+
|
109
|
+
color_depth = (@env['HTTP_X_UP_DEVCAP_SCREENDEPTH'].to_s =~ /^(\d+)/ && $1).to_i
|
110
|
+
colors = color_depth > 0 ? 2 ** color_depth : spec[7]
|
111
|
+
|
112
|
+
@display = Rack::Ketai::Display.new(:colors => colors,
|
113
|
+
:width => width,
|
114
|
+
:height => height)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Cookie対応
|
118
|
+
# 全機種対応(GW側で保持)
|
119
|
+
# SSL接続時はWAP2.0ブラウザ搭載端末でのみ端末に保持したCookieを送出
|
120
|
+
# http://www.au.kddi.com/ezfactory/tec/spec/cookie.html
|
121
|
+
def supports_cookie?
|
122
|
+
is_wap1? && use_ssl? ? false : true
|
123
|
+
end
|
124
|
+
|
125
|
+
# キャッシュサイズ
|
126
|
+
# HTTP_X_UP_DEVCAP_MAX_PDU に入ってくる…が一部古い携帯は入らないらしい
|
127
|
+
def cache_size
|
128
|
+
@cache_size ||= (val = @env['HTTP_X_UP_DEVCAP_MAX_PDU'].to_i) > 0 ? val : 8220
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def spec
|
133
|
+
@spec ||= SPECS[name] || []
|
134
|
+
end
|
135
|
+
|
136
|
+
def use_ssl?
|
137
|
+
@env['HTTPS'].to_s.downcase == 'on' || @env['X_FORWARDED_PROTO'] == 'https'
|
138
|
+
end
|
139
|
+
|
140
|
+
# WAP1ブラウザではKDDIからはじまらない
|
141
|
+
def is_wap1?
|
142
|
+
@env['HTTP_USER_AGENT'] !~ /^KDDI\-/
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# 変換テーブル読み込み
|
151
|
+
require 'rack/ketai/carrier/emoji/ausjisstrtoemojiid'
|
152
|
+
|
153
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# http://www.au.kddi.com/ezfactory/tec/spec/ezsava_ip.html
|
3
|
+
# 2010.6.22時点
|
4
|
+
|
5
|
+
Rack::Ketai::Carrier::Au::CIDRS = %w(
|
6
|
+
210.230.128.224/28
|
7
|
+
121.111.227.160/27
|
8
|
+
61.117.1.0/28
|
9
|
+
219.108.158.0/27
|
10
|
+
219.125.146.0/28
|
11
|
+
61.117.2.32/29
|
12
|
+
61.117.2.40/29
|
13
|
+
219.108.158.40/29
|
14
|
+
219.125.148.0/25
|
15
|
+
222.5.63.0/25
|
16
|
+
222.5.63.128/25
|
17
|
+
222.5.62.128/25
|
18
|
+
59.135.38.128/25
|
19
|
+
219.108.157.0/25
|
20
|
+
219.125.145.0/25
|
21
|
+
121.111.231.0/25
|
22
|
+
121.111.227.0/25
|
23
|
+
118.152.214.192/26
|
24
|
+
118.159.131.0/25
|
25
|
+
118.159.133.0/25
|
26
|
+
118.159.132.160/27
|
27
|
+
111.86.142.0/26
|
28
|
+
111.86.141.64/26
|
29
|
+
111.86.141.128/26
|
30
|
+
111.86.141.192/26
|
31
|
+
118.159.133.19/26
|
32
|
+
).collect{ |cidr| IPAddr.new(cidr) }
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# http://www.nttdocomo.co.jp/service/imode/make/content/ip/index.html
|
3
|
+
# 2010.4.19時点
|
4
|
+
|
5
|
+
Rack::Ketai::Carrier::Docomo::CIDRS = %w(
|
6
|
+
210.153.84.0/24
|
7
|
+
210.136.161.0/24
|
8
|
+
210.153.86.0/24
|
9
|
+
124.146.174.0/24
|
10
|
+
124.146.175.0/24
|
11
|
+
202.229.176.0/24
|
12
|
+
202.229.177.0/24
|
13
|
+
202.229.178.0/24
|
14
|
+
).collect{ |cidr| IPAddr.new(cidr) }
|