Chrome拡張のバックグラウンドのDOMを取得する方法

chrome.extension.getBackgroundPage().document

これでバックグラウンドページのDOMを取得できる。

またバックグランド内で定義された変数hogeも取得できる

<script>
// background.html
var hoge = null;
</script>
<script>
// NOT_backgroud.html
chrome.extension.getBackgroundPage().hoge
</script>

このサンプルを見て知った : http://code.google.com/chrome/extensions/samples.html#56a8d2ac24ca7bba78fd88ad57f43fc13c784497

  • background.html
  • contacts.html

Google Chrome 拡張機能でOAuthを利用する方法

記事について

GoogleカレンダーAPIを使って拡張機能を作りたかったけど、OAuthでの認証が必要と分かった。色々調べていると認証が通ったので、そのメモ書き。

拡張機能でOAuthを利用する際に問題になること

  1. CONSUMER_KEYやCONSUMER_SECRETを公開してしまうこと
  2. 認証の際に別URLへコールバックされること

1に関して。
Googleのカレンダーやコンタクトや何やらのGoogle Data APIを叩きたかったら、OAuthで認証する必要がある。OAuthは通常CONSUMER_KEYやCONSUMER_SECRETをサービス提供側が事前に取得する必要がある。この2つのキーは他人に公開すると悪用される場合があるため、教えてはならない。

2に関して。
OAuthの仕様上、認証に必要なキーを取得するためにコールバックで別のURLを飛ばされてしまう。コールバックのURLにはhttp://*https:// しか指定できず、Chrome拡張機能を示すchrome-extension://*は指定できない。

解決策

問題1の解決策は、CONSUMER_KEYとCONSUMER_SECRETに両方'anonymous'を入れるだけ。
問題2に関して。
Chrome APIのサンプルにOAuth機能を実現するサンプルが有る。Sample - OAuth Contacts
このサンプルを実行するとユーザのコンタクト情報が取得できたことが分かる。今回はこの中の

3ファイルを利用する。これらのファイルは拡張機能でOAuthを実現するために必要なファイルである。chrome_ex_ouath.htmlはコールバック先のファイルである。内部でどういった動作をしているかはわからないので、解説はできない。

実装

以下のプログラムはGoogleカレンダーAPIを使い予定を登録するプログラムである。
まずmanifest.jsonにはこのように書く。

{
    ...
    "background_page": "background.html",
    "permissions": [
        "tabs",
        "http://www.google.com/calendar/feeds/*",
        "https://www.google.com/accounts/OAuthGetRequestToken",
        "https://www.google.com/accounts/OAuthAuthorizeToken",
        "https://www.google.com/accounts/OAuthGetAccessToken"
    ],
    ...
}

background.htmlで認証処理を行わせる。認証の際にドメインを複数またぐので、その許可を求める。
今回はGoogleOAuth認証を行うのでそれ用の設定をしたが、Twitterに関しては別の方が書かれていた。Loading...

background.htmlで行わせる処理。

...
<script src="OAuthSimple/chrome_ex_oauth.js"></script>
<script src="OAuthSimple/chrome_ex_oauthsimple.js"></script>
<script>
var oauth = ChromeExOAuth.initBackgroundPage({
        'request_url' : 'https://www.google.com/accounts/OAuthGetRequestToken',
        'authorize_url' : 'https://www.google.com/accounts/OAuthAuthorizeToken',
        'access_url' : 'https://www.google.com/accounts/OAuthGetAccessToken',
        'consumer_key' : 'anonymous',
        'consumer_secret' : 'anonymous',
        'scope' : 'http://www.google.com/calendar/feeds/',
        'app_name' : 'Application Name'
});
window.chromeExOAuth.callback_page = 'OAuthSimple/chrome_ex_oauth.html';

oauth.authorize(function() {
    var url = "http://www.google.com/calendar/feeds/default/private/full";
    var body = JSON.stringify({
        "data": { "title": "Tennis with Beth",
            "details": "Meet for a quick lesson.",
            "transparency": "opaque",
            "status": "confirmed",
            "location": "Rolling Lawn Courts",
            "when": [
            {
                "start": "2010-04-17T15:00:00.000Z",
                "end": "2010-04-17T17:00:00.000Z"
            }
            ]
        }
    });
    oauth.sendSignedRequest(url,
    function(text, xhr) {
        console.log(text);
    },
    {
        'method': 'POST',
        'headers': {'GData-Version': '2', 'Content-Type': 'application/json'},
        'body': body
    });
});

...
</script>
...

ChromeのOAuthサンプルのファイルを読み込ませる。その後に、ChromeExOAuth.initBackgroundPage APIを使い認証の設定させる。問題1の解決策で書いたようにconsumer_keyとconsumer_secretに'anonymous'を入れる。
次の行に関してだが、これはコールバックURLの変更する手続きである。コールバックURLのデフォルトは'chrome_ex_oauth.html'となっている。変更するオプションも同APIに存在するが、変更出来なかった。chrome_ex_oauth.jsの関係するコードを読むと設定方法が分かった。windos.chromeExOAuth.callback_pageに任意のコールバックURLを入れることで設定ができた。

oauth.authorizeで認証を行わせる。引数の関数はtokenが取得できた時に呼ばれる関数である。ここで初めて、GoogleカレンダーAPIを使い予定を登録したり取得することが可能となる。

最後にGoogle カレンダーAPIを使い予定を登録する。そのためのAPIこれ。POSTメソッドを使い予定を送信する。この時JSONフォーマットで送るので

Content-Type: application/json
GData-Version: 2

とした。このヘッダ情報に加えてGoogle Data APIのバージョンも追加しておいた。今回のプログラムではバージョン情報を追加しなくとも動くことが確認できた。

これらの情報を送信するAPIはoauth.sendSignedRequestである。引数はそれぞれ、APIのURL、送信後のレスポンスを受け取る関数、送信情報である。

終りに

GoogleカレンダーAPIをつかって予定を登録することができた。手こずったのは予定を登録する処理である。APIのドキュメントを読みながらやっていたからである。

以上メモ書き。

Chrome拡張機能「ニコ生を見る予定」を作りました


この拡張について

ニコ生の放送予定をGoogleカレンダーに書く込むのがすごく面倒、そんな面倒を解決するのがこの拡張機能です。
2クリックでGoogleカレンダーの予定を作成します。


操作方法は簡単!放送予定で[Googleカレンダー]ボタンを押し、予定作成ページに移動したら[作成]ボタンを押すだけです。

Visual C++を使っていてスタックオーバーフローが起こった

問題


Visual C++プログラムを書き、デバッグしていたら、スタックオーバーフローが起こった。

原因

参考資料スタックオーバーフロー - Wikipedia
どうや大量に変数を宣言したのが原因かもしれない。
関数を呼び出しすぎて問題が起こったのではなさそうだ。なぜなら、呼び出し履歴を見ると10個ぐらいしか、関数が呼び出されていないからだ。

解決策

スタック領域のサイズを増やせば回避できる。


該当プロジェクトの[プロパティ]→[構成プロパティ]→[リンカー]→[システム]→[スタックのサイズの設定]に
適当な値を入力。
デフォルト値は1MBなので、今回は4MBを割り当てた。入力値の単位はバイトであることに注意。

Binary Hacks 0x00

O'Reilly Japan - Binary Hacksを読んでみた。

動機

読もうとした同期は、低レイヤに対するコンプレックスがあるから。PythonとかPerlとか色んな高級言語を使用してきたけど、なかでどんな事が起きているのかしりたかったから。C言語を勉強し始めたのもBasicの言語を学んでいて低レイヤに対するコンプレックスから。

こういった高レイヤにある技術を知るのに低レイヤの知識はあったほうが良いので、この本を手に取ってみた。思いのほか面白い内容が書かれていた。読了後、面白いと持ったテクニック(ハック)をチェックしたら、100個中32個あった。

この32個のハックを学習する上で時間があれば、このブログにメモしておこうと思う。

2011/11/12追記:と、思ったけど

ブログの記事にしようと思ったけど、大半が本のコピーになんるので、やめておく。

気になったハック

気になったハックだけメモしておく。
7. lddで共有ライブラリの依存関係をチェックする
14. c++filtでC++のシンボルをデマングルする
18. CとC++のプログラムをリンクするときの注意点
20. GNU/Linuxの共有ライブラリを作るときPICでコンパイルするのはなぜか
22. GCCGNU拡張入門
26. TLS(スレッドローカルストレージ)を使う
31. main()の前に関数を呼ぶ
43. -ftrapvで整数演算のオーバーフローを検出する
44. Mudflap でバッファオーバーフローを検出する
45. -D_FORTIFY_SOURCEでバッファオーバーフローを検出する
46. -fstack-protectorでスタックを保護する
49. 64ビット環境で0とNULLの違いに気を付ける
50. POSIXのスレッドセーフな関数
55. Valgrindでメモリの不正アクセスを検出する
56. Helgrindでマルチスレッドプログラムのバグを検出する
70. libdwarfでデバッグ情報を取得する
72. オブジェクトファイルを自力でロードする
74. GNU lightningでポータブルに実行時コード生成する
76. sigaltstackでスタックオーバーフローに対処する
77. 関数へのenter/exitをフックする
82. straceでシステムコールをトレースする
84. JockeyでLinuxのプログラムの実行を記録、再生する
85. prelinkでプログラムの起動を高速化する
87. gprofでプロファイルを調べる
88. sysprofでお手軽にシステムプロファイルを調べる
89. oprofileで詳細なシステムプロファイルを得る
90. GDBで実行中のプロセスを操る
92. Cのプログラムの中でブレークポイントを設定する
93. Boehm GCの仕組み
95. Portable Coroutine Library(PCL)で軽量な並行処理を行う
96. CPUのクロック数をカウントする
99. 結果が無限大やNaNになる演算でシグナルを発生させる

HTMLParserを使ってページのタイトルを取得

発端

ページのタイトルタグを取る必要があったので、正規表現で書こうかと思ったけど諦めた。理由はtitleタグには改行とかコメントアウトされている可能性があるから。

<title>
タイトルだよー
</title>
---------------------------------------------
<!-- <title>偽タイトル</title> -->
<title>こっちが本物のタイトル</title>

解決策

Python標準ライブラリ内にHTMLパーサのないかなと思って探したらHTMLParserというライブラリが見つかった。これを使いページのタイトルを取得してみた。
下記と同じ物HTMLParserを使ったページタイトルの取得 · GitHub

from HTMLParser import HTMLParser
import urllib2

class GetTitle(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.title_flag = False

    def handle_starttag(self, tag, attrs):
        if tag == 'title':
            self.title_flag = True

    def handle_data(self, data):
        if self.title_flag:
            self.title = data
            self.title_flag = False

def main():
    url = 'http://twitter.com'
    response = urllib2.urlopen(url)
    gt = GetTitle()
    gt.feed(response.read())
    gt.close()
    print '%s - %s' % (url, gt.title)

if __name__ == '__main__':
    main()

結果

取れた!

http://twitter.com - Twitter

参考文献

簡単なHTMLParserについて知れた htmllib.HTMLParserでリンクを抽出 - ひきメモ

gitで特定のファイルの履歴を消す方法

$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch targetfile' HEAD

これで、特定のファイルtargetfileの履歴を消去できる。
特定のディレクトリは

$ git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch dir' HEAD

で特定のディレクトリdirが消える。-rオプションを忘れずに。
後は、コミットするだけ。

$ git commit -m 'delete targetfile'

リモートのリポジトリにもこの変更を反映させなければならない。
そういう場合は

$ git push origin master --force

でプッシュ。--forceを付けたのはリモートを強制的に上書きするため。
まだ、リモートにはブランチがのこってるので、それを消去

$ git branch -d delete-branch
$ git push origin delete-ranch

参考サイト

特定のファイルの履歴を消す方法 : Redirecting...
リモートのbranchを消去する方法 : Git で不要になったローカルブランチ・リモートブランチの削除 - sotarokのお勉強